Difference between revisions of "Esercizi di "lettura" programmi in C"

From Sistemi Operativi
Jump to navigation Jump to search
(Created page with "Read carefully and describe the ''tricks'' used in these programs. = C language - No Libraries = The following programs do not use library functions (only printf, just to ha...")
 
 
(7 intermediate revisions by the same user not shown)
Line 210: Line 210:
 
void printxvowel(char v, char *s) {
 
void printxvowel(char v, char *s) {
 
   int s_len = slen(s);
 
   int s_len = slen(s);
   char locals[s_len];
+
   char locals[s_len + 1];
 
   int i;
 
   int i;
 
   for (i=0; i<s_len; i++) {
 
   for (i=0; i<s_len; i++) {
Line 263: Line 263:
 
     for (i = 0; i < rows_of(table ## X); i++)  \
 
     for (i = 0; i < rows_of(table ## X); i++)  \
 
       printf(#X " %02d %s\n",i,table ## X [i]); \
 
       printf(#X " %02d %s\n",i,table ## X [i]); \
     } while (0);
+
     } while (0)
  
 
char tableA[][50] = {"Sempre caro mi fu quest'ermo colle,",
 
char tableA[][50] = {"Sempre caro mi fu quest'ermo colle,",
Line 280: Line 280:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== typeof ==
+
== typeof/__auto_type==
(compiler extension)
+
(typeof: compiler extension, and C23)
  
 
<syntaxhighlight lang=C>
 
<syntaxhighlight lang=C>
Line 288: Line 288:
 
#define SWAP(X, Y) do { \
 
#define SWAP(X, Y) do { \
 
         typeof(Y) tmp = (X); \
 
         typeof(Y) tmp = (X); \
 +
        (X) = (Y); \
 +
        (Y) = tmp; \
 +
} while (0)
 +
 +
int main() {
 +
        int a = 2, b = 3;
 +
        char *s = "due", *t = "tre";
 +
        SWAP(a,b);
 +
        SWAP(s,t);
 +
        printf("%d %d\n", a, b);
 +
        printf("%s %s\n", s, t);
 +
}
 +
</syntaxhighlight>
 +
 +
(__auto_type: gcc and C23, as "auto"
 +
 +
<syntaxhighlight lang=C>
 +
#include <stdio.h>
 +
 +
#define SWAP(X, Y) do { \
 +
        __auto_type tmp = (X); \
 
         (X) = (Y); \
 
         (X) = (Y); \
 
         (Y) = tmp; \
 
         (Y) = tmp; \
Line 655: Line 676:
  
 
   return value;
 
   return value;
 +
}
 +
</syntaxhighlight>
 +
 +
== Command line args management (getopt + union) ==
 +
<syntaxhighlight lang=C>
 +
#include <stdio.h>
 +
#include <stdlib.h>
 +
#include <string.h>
 +
#include <getopt.h>
 +
 +
char short_options[] = "hf:vt:a:";
 +
struct option long_options[] = {
 +
  {"help", no_argument, NULL, 'h'},
 +
  {"file", required_argument, NULL, 'f'},
 +
  {"verbose", no_argument, NULL, 'v'},
 +
  {"test", required_argument, NULL, 't'},
 +
  {"addr", required_argument, NULL, 'a'},
 +
};
 +
 +
char optchars[] = "hfvta";
 +
union {
 +
  char *args[sizeof(optchars)];
 +
  struct {
 +
    char *help;
 +
    char *file;
 +
    char *verbose;
 +
    char *text;
 +
    char *addr;
 +
  };
 +
} opts;
 +
 +
void usage(void) {
 +
  exit(1);
 +
}
 +
 +
#ifndef _GNU_SOURCE
 +
const char *strchrnul(const char *s, int c) {
 +
  while (*s != 0 && *s != c)
 +
    s++;
 +
  return s;
 +
}
 +
#endif
 +
 +
void setarg(int c, char *optarg) {
 +
  int index = strchrnul(optchars, c) - optchars;
 +
  opts.args[index] = optarg ? optarg : "";
 +
}
 +
 +
int main(int argc, char *argv[]) {
 +
  int c = 0;
 +
  while (c != -1) {
 +
    c = getopt_long(argc, argv, short_options, long_options, NULL);
 +
    switch (c) {
 +
      case -1:
 +
        break;
 +
      case '?':
 +
        usage();
 +
      default:
 +
        setarg(c, optarg);
 +
        break;
 +
    }
 +
  }
 +
 +
  printf("%s \n", opts.help);
 +
  printf("%s \n", opts.file);
 +
  printf("%s \n", opts.verbose);
 +
  printf("%s \n", opts.text);
 +
  printf("%s \n", opts.addr);
 +
}
 +
</syntaxhighlight>
 +
 +
== Command line args management (getopt + union + preprocessor woodoo) ==
 +
<syntaxhighlight lang=C>
 +
#include <stdio.h>
 +
#include <stdlib.h>
 +
#include <getopt.h>
 +
#include <libgen.h>
 +
 +
#define AUTOPTS \
 +
  OPSOP(h, help, 0, "Display this help message") \
 +
  OPSOP(f, file, 1, "Set the file") \
 +
  OPSOP(v, verbose, 0, "Verbose mode") \
 +
  OPSOP(t, text, 1, "Text field") \
 +
  OPSOP(a, addr, 1, "Set the address")
 +
 +
#define _OPS0(...)
 +
#define _OPS1(...) ":"
 +
#define OPSOP(s, l, a, h) #s _OPS ## a(a)
 +
char short_options[] = AUTOPTS;
 +
#undef _OPS0
 +
#undef _OPS1
 +
#undef OPSOP
 +
 +
#define OPSOP(s, l, a, h) { #l, a, NULL, #s [0] },
 +
struct option long_options[] = {
 +
  AUTOPTS
 +
};
 +
#undef OPSOP
 +
 +
#define OPSOP(s, l, a, h) #s
 +
char optchars[] = AUTOPTS;
 +
#undef OPSOP
 +
 +
#define OPSOP(s, l, a, h) char *l ;
 +
union {
 +
  char *args[sizeof(optchars)];
 +
  struct {
 +
    AUTOPTS
 +
  };
 +
} opts;
 +
#undef OPSOP
 +
 +
void usage(char *progname) {
 +
#define _OPS0(...) "    "
 +
#define _OPS1(...) "<arg>"
 +
#define OPSOP(s, l, a, h) \
 +
  printf(" -%s, --%-8s %s        %s\n", #s, #l, _OPS ## a(a), h);
 +
  printf("%s [OPTIONS] file\nOptions:\n", progname);
 +
  AUTOPTS
 +
#undef _OPS0
 +
#undef _OPS1
 +
#undef OPSOP
 +
    printf("\n");
 +
  exit(1);
 +
}
 +
 +
#ifndef _GNU_SOURCE
 +
const char *strchrnul(const char *s, int c) {
 +
  while (*s != 0 && *s != c)
 +
    s++;
 +
  return s;
 +
}
 +
#endif
 +
 +
void setarg(int c, char *optarg) {
 +
  int index = strchrnul(optchars, c) - optchars;
 +
  opts.args[index] = optarg ? optarg : "";
 +
}
 +
 +
int main(int argc, char *argv[]) {
 +
  int c = 0;
 +
  char *progname = basename(argv[0]);
 +
  while (c != -1) {
 +
    c = getopt_long(argc, argv, short_options, long_options, NULL);
 +
    switch (c) {
 +
      case -1:
 +
        break;
 +
      case '?':
 +
        usage(progname);
 +
      default:
 +
        setarg(c, optarg);
 +
        break;
 +
    }
 +
  }
 +
 +
  printf("%s \n", opts.help);
 +
  printf("%s \n", opts.file);
 +
  printf("%s \n", opts.verbose);
 +
  printf("%s \n", opts.text);
 +
  printf("%s \n", opts.addr);
 +
  if (opts.help)
 +
    usage(progname);
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 781: Line 964:
  
 
== fantasy of strcpy (time, stdint, string) ==
 
== fantasy of strcpy (time, stdint, string) ==
Cit. [http://www.liberliber.it/mediateca/libri/r/rostand/cirano_di_bergerac/pdf/cirano_p.pdf Cirano] page 33.
+
 
 +
Cit. [http://copioni.corrierespettacolo.it/wp-content/uploads/2016/12/ROSTAND%20Edmond__Cirano%20di%20Bergerac__null__U(29)-D(13)__Commedia__5a.pdf Cirano] pag. 25.
 +
 
 +
Cit. orig. [http://www.crdp-strasbourg.fr/je_lis_libre/livres/Rostand_CyranoDeBergerac.pdf Cyrano] page 67.
 +
 
 
<syntaxhighlight lang=C>
 
<syntaxhighlight lang=C>
 
#include <stdio.h>
 
#include <stdio.h>

Latest revision as of 08:20, 20 September 2023

Read carefully and describe the tricks used in these programs.

C language - No Libraries

The following programs do not use library functions (only printf, just to have a feedback of the results).

Quine

#include<stdio.h>
char *s="#include<stdio.h>%cchar *s=%c%s%c;%cint main() {printf(s,10,34,s,34,10,10);}%c";
int main() {printf(s,10,34,s,34,10,10);}

int printf(const char *format, ...);char *s="int printf(const char *format, ...);char *s=%c%s%c;int main(){printf(s,34,s,34,10);};%c";int main(){printf(s,34,s,34,10);};

enum

#include <stdio.h>

enum numbers { zero, uno, due, quarantadue = 42 };

int main() {
        enum numbers n;
        n = 44;
        printf("%d %d %d %d %d\n", zero, uno, due, quarantadue, n);
}

arrays, pointers and structs

#include <stdio.h>

char *spoint="hello";
char sarr[]="hello";
struct strs {
  char s[6];
} sstruct = {"hello"};

void foo(char *s) {
  s[4]=0;
}

void bar(struct strs s) {
  s.s[4]=0;
  printf("from bar %s\n", s.s);
}

int main(int argc, char *argv[]) {
  printf("%s %s %s\n", spoint, sarr, sstruct.s);
  foo(sarr);
  printf("%s %s %s\n", spoint, sarr, sstruct.s);
  bar(sstruct);
  printf("%s %s %s\n", spoint, sarr, sstruct.s);
  // test the following statements, one at a time
  //spoint = sarr;
  //sarr = spoint;
  foo(spoint);
  printf("%s %s %s\n", spoint, sarr, sstruct.s);
}

alignment

#include <stdio.h>
  
struct A {
  char a1;
  long a2;
  char a3;
};

struct B {
  char b1;
  char b2;
  long b3;
};

int main() {
  printf("%d %d\n", sizeof(struct A), sizeof(struct B));
}

iteration and recursion

#include <stdio.h>

struct elem {
  int val;
  struct elem *next;
};

struct elem *head = NULL;

struct elem *rinsert(struct elem *new, struct elem *head) {
  if (head == NULL || new->val < head->val) {
    new->next = head;
    return new;
  } else {
    head->next = rinsert(new, head->next);
    return head;
  }
}

struct elem *iinsert(struct elem *new, struct elem *head) {
  struct elem **pnext;
  for (pnext = &head;
      *pnext != NULL && new->val > (*pnext)->val;
      pnext = &((*pnext)->next))
    ;
  new->next = *pnext;
  *pnext = new;
  return head;
}

void rprint(struct elem *this) {
  if (this) {
    printf("%d ",this->val);
    rprint(this->next);
  }
}

void iprint(struct elem *this) {
  for ( ; this != NULL; this = this->next)
    printf("%d ",this->val);
}

struct elem test[]={{5},{3},{9},{1},{7}};
#define NELEM (sizeof(test) / sizeof(struct elem))

int main(int argc, char *argv[]) {
  int i;
  for (i = 0; i < NELEM; i++)
    head = rinsert(&test[i], head);
  rprint(head);
  printf("\n");
  iprint(head);
  printf("\n");
  head = NULL;
  for (i = 0; i < NELEM; i++)
    head = iinsert(&test[i], head);
  rprint(head);
  printf("\n");
  iprint(head);
  printf("\n");
}

comma operator

#include <stdio.h>

int main() {
        int a, b;
        a = 1, 2, 3;
        b = (1, 2, 3);
        printf("%d %d\n", a, b);
}

#include <stdio.h>

int slen(char *s) { /* in real programs use strlen instead */
  size_t rval;
  for (rval = 0; *s != 0; s++, rval++)
    ;
  return rval;
}

int ispal(char *s) {
  int i,j;
  for (i=0, j=slen(s)-1; i < j; i++, j--) {
    if (s[i] != s[j])
      return 0;
  }
  return 1;
}

void reverse(char *s) {
  int i,j;
  for (i=0, j=slen(s)-1; i < j; i++, j--)
    s[j] ^= s[i] ^= s[j] ^= s[i];
}

int main(int argc, char *argv[1]) {
  for ( ;argc > 1; argv++, argc--) {
    printf("\"%s\" is%s palindrome\n", argv[1],
        ispal(argv[1])?"":"n't");
    reverse(argv[1]);
    printf("\"%s\"\n", argv[1]);
  }
}

string by value

#include <stdio.h>

int slen(char *s) { /* in real programs use strlen instead */
  int rval;
  for (rval = 0; *s != 0; s++, rval++)
    ;
  return rval;
}

void printxvowel(char v, char *s) {
  int s_len = slen(s);
  char locals[s_len + 1];
  int i;
  for (i=0; i<s_len; i++) {
    switch (s[i]) {
      case 'a':
      case 'e':
      case 'i':
      case 'o':
      case 'u':
        locals[i] = v;
        break;
      default:
        locals[i] = s[i];
        break;
    }
  }
  printf("-> %s\n<- %s\n",s,locals);
}

int main(int argc, char *argv[]) {
  for ( ; argc > 1; argc--, argv++) {
    printxvowel('a',argv[1]);
    printxvowel('e',argv[1]);
    printxvowel('i',argv[1]);
    printxvowel('o',argv[1]);
    printxvowel('u',argv[1]);
  }
  return 0;
}

test it using "Garibaldi fu ferito, fu ferito ad una gamba, Garibaldi che comanda, che comanda il battaglion" as argv[1].

preprocessor Quine

#define Q(x)char*s=#x;x
Q(int printf(const char *format, ...);int main(){printf("#define Q(x)char*s=#x;x\nQ(%s)\n",s);})

tables and preprocessor tricks

#include <stdio.h>

#define rows_of(X) (sizeof(X) / sizeof((X)[0]))

#define printTable(X) do { \
    int i; \
    printf("TABLE " #X ": size of element %d\n" \
        "(printed by the line %d of source file %s)\n",  \
        sizeof(*(table ## X)), __LINE__, __FILE__); \
    for (i = 0; i < rows_of(table ## X); i++)  \
      printf(#X " %02d %s\n",i,table ## X [i]); \
    } while (0)

char tableA[][50] = {"Sempre caro mi fu quest'ermo colle,",
  "e questa siepe, che da tanta parte",
  "dell’ultimo orizzonte il guardo esclude."};
char *tableB[] = {"Sempre caro mi fu quest'ermo colle,",
  "e questa siepe, che da tanta parte",
  "dell’ultimo orizzonte il guardo esclude."};

int main(int argc, char *argv[1]) {
  int i;
  printTable(A);
  printf("\n");
  printTable(B);
}

typeof/__auto_type

(typeof: compiler extension, and C23)

#include <stdio.h>

#define SWAP(X, Y) do { \
        typeof(Y) tmp = (X); \
        (X) = (Y); \
        (Y) = tmp; \
} while (0)

int main() {
        int a = 2, b = 3;
        char *s = "due", *t = "tre";
        SWAP(a,b);
        SWAP(s,t);
        printf("%d %d\n", a, b);
        printf("%s %s\n", s, t);
}

(__auto_type: gcc and C23, as "auto"

#include <stdio.h>

#define SWAP(X, Y) do { \
        __auto_type tmp = (X); \
        (X) = (Y); \
        (Y) = tmp; \
} while (0)

int main() {
        int a = 2, b = 3;
        char *s = "due", *t = "tre";
        SWAP(a,b);
        SWAP(s,t);
        printf("%d %d\n", a, b);
        printf("%s %s\n", s, t);
}

arrays and pointers

#include <stdio.h>

int slen(char *s) { /* in real programs use strlen instead */
  size_t rval;
  for (rval = 0; *s != 0; s++, rval++)
    ;
  return rval;
}

void echoargs(int argc, char *argv[]) {
  int i;
  for (i = 0; i < argc; i++)
    printf("argv[%d] = \"%s\"\n",i,argv[i]);
  printf("\n");
}

enum state {SPACE, CHAR};

int splitargv(char *s, char **argv) {
  enum state state = SPACE;
  int count = 0;
  for (; *s != 0; s++) {
    if (*s == ' ' || *s == '\t' || *s == '\n') {
      if (state != SPACE)
        count++;
      if (argv != NULL)
        *s = 0;
      state = SPACE;
    } else {
      if (state == SPACE && argv != NULL)
        *argv++ = s;
      state = CHAR;
    }
  };
  if (state != SPACE)
    count++;
  if (argv != NULL)
    *argv = NULL;
  return count;
}

void splitargs(char *args) {
  int newargc = splitargv(args, NULL);
  char *newargv[newargc + 1];
  splitargv(args, newargv);
  echoargs(newargc, newargv);
}

int main(int argc, char *argv[1]) {
  echoargs(argc, argv);
  for ( ; *argv != NULL; argv++) {
    printf("Split \"%s\"\n",*argv);
    splitargs(*argv);
  }
}

This is a simplified version of the idea used in the libexecs library. Test this program using args like:

./a.out "ciao               mare" "a      b c"

void * and function pointers

#include <stdio.h>

typedef void (*voidfun) (void *arg);

void printint(void *arg) {
  int *iarg = arg;
  printf("int %d\n", *iarg);
}

void printstring(void *arg) {
  char *sarg = arg;
  printf("int %s\n", sarg);
}

void printpointer(void *arg) {
  printf("pointer %p\n", arg);
}

void printfun(void *arg) {
  voidfun fun = arg;
  fun((void *) 0x42);
}

void launch(voidfun f, void *opaque) {
  f(opaque);
}

int main(int argc, char *argv[1]) {
  int v = 235;
  char *s = "Lasciate ogni speranza, o voi ch'entrate";
  launch(printint, &v);
  launch(printstring, s);
  launch(printfun, printpointer);
  return 0;
}

This technique is used to implement callbacks with opaque args.

Programs using libraries

char by char copy (stdio)

#include <stdio.h>

int main(int argc, char *argv[]) {
  int c;
  while ((c = getchar()) != EOF)
    putchar(c);
}

similar programs, different approaches (stdio, string, stdlib, ctype)

First program:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#define BUFLEN 4096

char *loadfile(char *path) {
  char *contents = NULL;
  size_t contents_len = 0;
  char buffer[BUFLEN];
  size_t len;
  FILE *fin = fopen(path, "r");
  FILE *fout = open_memstream(&contents, &contents_len);
  if (fin == NULL || fout == NULL)
    exit(1);
  while ((len = fread(buffer, sizeof(char), BUFLEN, fin)) > 0)
    fwrite(buffer, sizeof(char), len, fout);
  fclose(fin);
  fclose(fout);
  return(contents);
}

enum state {SPACE, CHAR};

int splitwords(char *s, char **words) {
  enum state state = SPACE;
  int count = 0;
  for (; *s != 0; s++) {
    if (isalnum(*s)) {
      if (state == SPACE && words != NULL)
        *words++ = s;
      state = CHAR;
    } else {
      if (state != SPACE)
        count++;
      if (words != NULL)
        *s = 0;
      state = SPACE;
    }
  };
  if (state != SPACE)
    count++;
  return count;
}

static int sortcmp(const void *p1, const void *p2) {
  const char *s1 = *(char * const *) p1;
  const char *s2 = *(char * const *) p2;
  int rval = strlen(s1) - strlen(s2);
  if (rval == 0)
    rval = strcmp(s1, s2);
  return rval;
}

int main(int argc, char *argv[1]) {
  if (argc == 2) {
    char *contents = loadfile(argv[1]);
    int count = splitwords(contents, NULL);
    char **words = malloc(count * sizeof(char *));
    if (words == NULL)
      return 1;
    else {
      int i;
      splitwords(contents, words);
      qsort(words, count, sizeof(char *), sortcmp);
      for (i = 0; i < count; i++)
        printf("%s\n", words[i]);
      return 0;
    }
  } else
    return 1;
}

Second program:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

struct word {
  struct word *next;
  int count;
  char word[0];
};

static int lenalphacmp(const char *s1, const char *s2) {
  int rval = strlen(s1) - strlen(s2);
  if (rval == 0)
    rval = strcmp(s1, s2);
  return rval;
}

struct word *addword(char *word, struct word *wlist) {
  struct word **scan;
  int cmpvalue;
  for (scan = &wlist;
      *scan != NULL && ((cmpvalue = lenalphacmp(word, (*scan)->word)) > 0);
      scan = &((*scan)->next))
    ;
  if (scan != NULL && cmpvalue == 0)
    (*scan)->count ++;
  else {
    struct word *new = malloc(sizeof(struct word) + strlen(word) + 1);
    if (new) {
      new->next = *scan;
      new->count = 1;
      strcpy(new->word, word);
      *scan = new;
    }
  }
  return wlist;
}

struct word *addwordlen(char *word, size_t len,  struct word *wlist) {
  char word0[len+1];
  strncpy(word0,word,len);
  word0[len]=0;
  return addword(word0, wlist);
}

struct word *processline(char *line, struct word *wlist) {
  char *thisword = NULL;
  for ( ;*line != 0; line++) {
    if (isalnum(*line)) {
      if (thisword == NULL)
        thisword = line;
    } else {
      if (thisword != NULL) {
        wlist = addwordlen(thisword, line - thisword, wlist);
        thisword = NULL;
      }
    }
  }
  return wlist;
}

void printwlist(struct word *wlist) {
  for ( ; wlist != NULL; wlist = wlist->next)
    printf("%s : %d\n", wlist->word, wlist->count);
}

int main(int argc, char *argv[1]) {
  if (argc == 2) {
    FILE *fin = fopen(argv[1], "r");
    ssize_t len;
    char *linebuf = NULL;
    size_t linebuflen = 0;
    struct word *wlist = NULL;
    while ((len = getline(&linebuf, &linebuflen, fin)) > 0)
      wlist = processline(linebuf, wlist);
    fclose(fin);
    free(linebuf);
    printwlist(wlist);
    return 0;
  } else
    return 1;
}

Command line args management (getopt)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <libgen.h>

void usage_and_exit(char *progname) {
  fprintf(stderr,
      "Usage:\n"
      "  %s OPTIONS [value] ... [value]\n"
      "Options:\n"
      "  -v | --verbose:      verbose mode\n"
      "  -h | --help:         print a short usage helping message\n"
      "  -a val | --add val   add a value\n"
      "  -s val | --sub val   subtract a value\n"
      "  --double             double the final result\n"
      "This program computes an integer value\n", progname);
  exit(1);
}

int main(int argc, char *argv[]) {
  static struct option long_options[] = {
    {"verbose", no_argument, 0, 'v'},
    {"help",    no_argument, 0, 'h'},
    {"add",     required_argument, 0, 'a'},
    {"sub",     required_argument, 0, 's'},
    {"double",  no_argument, 0, 0x101},
    {0,         0,           0, 0}
  };
  static char *short_options = "vha:s:";

  int opt;

  int value = 0;
  int verbose = 0;
  int doubleval = 1;

  char *progname = basename(argv[0]);

  while((opt = getopt_long(argc, argv, short_options, long_options, NULL)) > 0) {
    switch (opt) {
      case 'v': verbose = 1;
                break;
      case 'a': value += atoi(optarg);
                break;
      case 's': value -= atoi(optarg);
                break;
      case 0x101: doubleval *= 2;
                  break;
      case 'h':
      case '?': usage_and_exit(progname);
                break;
    }
  }
  
  for (; optind < argc; optind++)
    value += atoi(argv[optind]);

  value *= doubleval;

  if (verbose)
    printf("the result is %d\n", value);

  return value;
}

Command line args management (getopt + union)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>

char short_options[] = "hf:vt:a:";
struct option long_options[] = {
  {"help", no_argument, NULL, 'h'},
  {"file", required_argument, NULL, 'f'},
  {"verbose", no_argument, NULL, 'v'},
  {"test", required_argument, NULL, 't'},
  {"addr", required_argument, NULL, 'a'},
};

char optchars[] = "hfvta";
union {
  char *args[sizeof(optchars)];
  struct {
    char *help;
    char *file;
    char *verbose;
    char *text;
    char *addr;
  };
} opts;

void usage(void) {
  exit(1);
}

#ifndef _GNU_SOURCE
const char *strchrnul(const char *s, int c) {
  while (*s != 0 && *s != c)
    s++;
  return s;
}
#endif

void setarg(int c, char *optarg) {
  int index = strchrnul(optchars, c) - optchars;
  opts.args[index] = optarg ? optarg : "";
}

int main(int argc, char *argv[]) {
  int c = 0;
  while (c != -1) {
    c = getopt_long(argc, argv, short_options, long_options, NULL);
    switch (c) {
      case -1:
        break;
      case '?':
        usage();
      default:
        setarg(c, optarg);
        break;
    }
  }

  printf("%s \n", opts.help);
  printf("%s \n", opts.file);
  printf("%s \n", opts.verbose);
  printf("%s \n", opts.text);
  printf("%s \n", opts.addr);
}

Command line args management (getopt + union + preprocessor woodoo)

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <libgen.h>

#define AUTOPTS \
  OPSOP(h, help, 0, "Display this help message") \
  OPSOP(f, file, 1, "Set the file") \
  OPSOP(v, verbose, 0, "Verbose mode") \
  OPSOP(t, text, 1, "Text field") \
  OPSOP(a, addr, 1, "Set the address")

#define _OPS0(...)
#define _OPS1(...) ":"
#define OPSOP(s, l, a, h) #s _OPS ## a(a)
char short_options[] = AUTOPTS;
#undef _OPS0
#undef _OPS1
#undef OPSOP

#define OPSOP(s, l, a, h) { #l, a, NULL, #s [0] },
struct option long_options[] = {
  AUTOPTS
};
#undef OPSOP

#define OPSOP(s, l, a, h) #s
char optchars[] = AUTOPTS;
#undef OPSOP

#define OPSOP(s, l, a, h) char *l ;
union {
  char *args[sizeof(optchars)];
  struct {
    AUTOPTS
  };
} opts;
#undef OPSOP

void usage(char *progname) {
#define _OPS0(...) "     "
#define _OPS1(...) "<arg>"
#define OPSOP(s, l, a, h) \
  printf(" -%s, --%-8s %s         %s\n", #s, #l, _OPS ## a(a), h);
  printf("%s [OPTIONS] file\nOptions:\n", progname);
  AUTOPTS
#undef _OPS0
#undef _OPS1
#undef OPSOP
    printf("\n");
  exit(1);
}

#ifndef _GNU_SOURCE
const char *strchrnul(const char *s, int c) {
  while (*s != 0 && *s != c)
    s++;
  return s;
}
#endif

void setarg(int c, char *optarg) {
  int index = strchrnul(optchars, c) - optchars;
  opts.args[index] = optarg ? optarg : "";
}

int main(int argc, char *argv[]) {
  int c = 0;
  char *progname = basename(argv[0]);
  while (c != -1) {
    c = getopt_long(argc, argv, short_options, long_options, NULL);
    switch (c) {
      case -1:
        break;
      case '?':
        usage(progname);
      default:
        setarg(c, optarg);
        break;
    }
  }

  printf("%s \n", opts.help);
  printf("%s \n", opts.file);
  printf("%s \n", opts.verbose);
  printf("%s \n", opts.text);
  printf("%s \n", opts.addr);
  if (opts.help)
    usage(progname);
}

dynamic allocation on the heap, qsort, getline (stdlib)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define AOS_LENSTEP 8

struct array_of_strings {
    char **strings;
    size_t currentlength; 
    size_t arraylength;
};

typedef struct array_of_strings array_of_strings;

void array_of_strings_add(array_of_strings *arrayOfStrings, char *string) {
    if (arrayOfStrings->currentlength >= arrayOfStrings->arraylength) {
        size_t newlength = arrayOfStrings->arraylength + AOS_LENSTEP;
        char **new_string = realloc(arrayOfStrings->strings, newlength * sizeof(arrayOfStrings->strings[0]));
        if (new_string != NULL) {
            arrayOfStrings->arraylength = newlength;
            arrayOfStrings->strings = new_string;
        }
    }
    if (arrayOfStrings->currentlength < arrayOfStrings->arraylength)
        arrayOfStrings->strings[arrayOfStrings->currentlength++] = strdup(string);
}

void array_of_strings_print(array_of_strings *v) {
    size_t i;
    for (i = 0; i < v->currentlength; i++)
        printf("[%3lu]: %s\n", i, v->strings[i]);
}

static int alphasort(const void *a, const void *b) {
    return strcmp(*(char **) a, *(char **) b);
}

void array_of_strings_sort(array_of_strings *v) {
    qsort(v->strings, v->currentlength, sizeof(v->strings[0]), alphasort);
}

void array_of_strings_free(array_of_strings *v) {
    size_t i;
    for (i = 0; i < v->currentlength; i++)
        free(v->strings[i]);
    if (v->arraylength > 0)
        free(v->strings);
}

int main(int argc, char *argv[]) {
    char* line = NULL;
    size_t lineLength = 0;
    ssize_t numberOfCharactersRead;
    static array_of_strings arrayOfStrings;
    if (argc != 1)
        exit(1);
    while ((numberOfCharactersRead = getline(&line, &lineLength, stdin)) >= 0) {
        if (line[numberOfCharactersRead - 1] == '\n')
            line[numberOfCharactersRead - 1] = 0;
        array_of_strings_add(&arrayOfStrings, line);
    }

    free(line);
    array_of_strings_sort(&arrayOfStrings);
    array_of_strings_print(&arrayOfStrings);
    array_of_strings_free(&arrayOfStrings);
}

open_memstream (quite tricky)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
static int alphasort(const void *a, const void *b) {
  return strcmp(* (char **) a, * (char **) b);
}
 
int main(int argc, char *argv[]) {
  char *line = NULL;
  size_t lineLength = 0;
  ssize_t numberOfCharacterRead;
  FILE *fakefile;
  char *fakeMemoryFile = NULL;
  char **stringsarray;
  size_t stringsArrayLength = 0;
  char **scan;
  char *dups;
  if (argc != 1)
    exit(1);

  fakefile = open_memstream(&fakeMemoryFile, &stringsArrayLength);
  if (fakefile == NULL)
    exit(1);
 
  while ((numberOfCharacterRead = getline(&line, &lineLength, stdin)) >= 0) {
    if (line[numberOfCharacterRead - 1] == '\n')
      line[numberOfCharacterRead - 1] = 0;
    if ((dups = strdup(line)) != NULL)
      fwrite(&dups, sizeof(dups), 1, fakefile);
  }
 
  free(line);
  dups = NULL;
  fwrite(&dups, sizeof(dups), 1, fakefile);
  fclose(fakefile);
  stringsarray = (char **) fakeMemoryFile;
  stringsArrayLength /= sizeof(char *);
  stringsArrayLength--;
  printf("%lu\n",stringsArrayLength);
  qsort(stringsarray, stringsArrayLength, sizeof(stringsarray[0]), alphasort);
  for (scan = stringsarray; *scan != NULL; scan++)
    printf("[%3lu]: %s\n", scan - stringsarray, *scan);
  for (scan = stringsarray; *scan != NULL; scan++)
    free(*scan);
  free(stringsarray);
}

fantasy of strcpy (time, stdint, string)

Cit. Cirano pag. 25.

Cit. orig. Cyrano page 67.

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <time.h>

char *strcpy0(char *dest, const char *src) {
  int i;
  int len;
  for (len = 0; src[len] != 0; len++)
    ;
  for (i = 0; i <= len; i++)
    dest[i] = src[i];
  return dest;
}
 
char *strcpy1(char *dest, const char *src) {
  int i;
  for (i = 0; src[i] != 0; i++)
    ;
  for ( ; i >= 0; i--)
    dest[i] = src[i];
  return dest;
}
 
char *strcpy2(char *dest, const char *src) {
  char *rval = dest;
  while ((*dest++ = *src++) != 0)
    ;
  return rval;
}

char *strcpy3(char *dest, const char *src) {
  int i;
  for (i=0; (dest[i] = src[i]) != 0; i++)
    ;
  return dest;
}

char *strcpy4(char *dest, const char *src) {
  if ((*dest = *src) != 0)
    strcpy4(dest+1, src+1);
  return dest;
}


char *strcpy5(char *dest, const char *src) {
  char *rval = dest;
  while (*src != 0)
    *dest++ = *src++;
  *dest = 0;
  return rval;
}

char *strcpy6(char *dest, const char *src) {
  uint64_t *src64 = (uint64_t *) src;
  uint64_t *dest64 = (uint64_t *) dest;
  while (1) {
    register uint64_t tmp = *src64;
    register uint64_t scan;
    for (scan = 0xffULL; (tmp & scan) != 0; scan <<= 8)
      ;
      //printf("%llx %llx %p %p %s\n",scan, tmp, src64, dest64, (char *) src64);
    if (scan != 0) {
      strcpy2((char *) dest64, (char *) src64);
      break;
    }
    *dest64++ = tmp;
    src64++;
  }
  return dest;
}
 
#define NUMBER_OF_TEST 1000000
 
double time_strcpy(char * (*cpy)(char *, const char *), char *d, const char *s)
{
    clock_t starttime, time;
    int i;
    starttime = clock();
    for (i = 0; i< NUMBER_OF_TEST; i++)
    cpy(d, s);
    time = clock() - starttime;
    return (1.0) * time / CLOCKS_PER_SEC;
}

#define TESTSTRCPY(N,D,S) \
  printf("strcpy" #N " %s time %lf\n", strcpy ##N ((D),(S)), time_strcpy(strcpy ##N, (D),(S))) 
 
int main(int argc, char *argv[]) {
  if (argc != 2)
    return 1;
  else {
    size_t argv1len=strlen(argv[1]);
    char argcpy[argv1len+1];
    strncpy(argcpy, argv[1], argv1len);
    printf("strncpy %s\n", argcpy);
    TESTSTRCPY(, argcpy, argv[1]);
    TESTSTRCPY(0, argcpy, argv[1]);
    TESTSTRCPY(1, argcpy, argv[1]);
    TESTSTRCPY(2, argcpy, argv[1]);
    TESTSTRCPY(3, argcpy, argv[1]);
    TESTSTRCPY(4, argcpy, argv[1]);
    TESTSTRCPY(5, argcpy, argv[1]);
    TESTSTRCPY(6, argcpy, argv[1]);
  }
}

This program compares several homemade implementations of string copy functions with the library one.

math and printf

#include <stdio.h>
#include <unistd.h>
#include <math.h>
 
#define DELAY 10000
#define DURATION 30
 
int main(int argc, char *argv[]) {
  double x;
  int i;
  for (i = 0; i < DURATION * 1000000 / DELAY; i++) {
    double y = sin(M_PI * i / 100);
    int pos = 40 + (40 * y);
    printf("\r%*s\b",pos,"*");
    fflush(stdout);
    usleep(DELAY);
    printf("\n");
  }
}

minishell (history and execs)

this program needs some libraries: history/readline should be provided in yur distribution, execs is in Debian Buster (or it is available in GitHUB).

#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <execs.h>

int main(int argc, char *argv[]) {
  while (1) {
    char *cmd = readline("% ");
    if (cmd == NULL)
      break;
    if (*cmd != 0) {
      add_history(cmd);
      system_nosh(cmd);
    }
    free(cmd);
  }
  printf("\n");
  return 0;
}

You may need to define the environment variable LD_LIBRARY_PATH to load locally installed libraries.

LD_LIBRARY_PATH=/usr/local/lib
export LD_LIBRARY_PATH

conversions (math)

#include <stdio.h>
#include <math.h>

int main() {
  char c;
  short s;
  int i;
  long l;
  long long ll;
  unsigned char uc;
  unsigned short us;
  unsigned int ui;
  unsigned long ul;
  unsigned long long ull;
  float f;
  double d;
  long double ld;

  c = s = i = l = ll = 0xc1c2c3c4c5c6c7c8;
  printf("%d %llx %lld\n", sizeof(ll), ll, ll);
  printf("%d %lx %ld\n", sizeof(l), l, l);
  printf("%d %x %d\n", sizeof(i), i, i);
  printf("%d %x %d\n", sizeof(s), s, s);
  printf("%d %x %d\n", sizeof(c), c, c);

  ll = l = i = s = c;
  printf("%d %x %d\n", sizeof(s), s, s);
  printf("%d %x %d\n", sizeof(i), i, i);
  printf("%d %lx %ld\n", sizeof(l), l, l);
  printf("%d %llx %lld\n", sizeof(ll), ll, ll);
  
  i = 1 << (sizeof(i) * 8 - 1);
  printf("%d %x %d\n", sizeof(i), i, i);
  i >>= 1;
  printf("%d %x %d\n", sizeof(i), i, i);
  i = -1;
  printf("%d %x %d\n", sizeof(i), i, i);
  i >>= 1;
  printf("%d %x %d\n", sizeof(i), i, i);

  uc = us = ui = ul = ull = 0xc1c2c3c4c5c6c7c8;
  printf("%d %llx %llu\n", sizeof(ull), ull, ull);
  printf("%d %lx %lu\n", sizeof(ul), ul, ul);
  printf("%d %x %u\n", sizeof(ui), ui, ui);
  printf("%d %x %u\n", sizeof(us), us, us);
  printf("%d %x %u\n", sizeof(uc), uc, uc);
  ull = ul = ui = us = uc;
  printf("%d %x %u\n", sizeof(us), us, us);
  printf("%d %x %u\n", sizeof(ui), ui, ui);
  printf("%d %lx %lu\n", sizeof(ul), ul, ul);
  printf("%d %llx %llu\n", sizeof(ull), ull, ull);

  f = d = ld = acosl(-1);
  printf("%2d %80.78llf\n", sizeof(ld), ld);
  printf("%2d %80.78lf\n", sizeof(d), d);
  printf("%2d %80.78f\n", sizeof(f), f);

  return 0;
}

Explanation of program's output for a LP64 architecture:

8 c1c2c3c4c5c6c7c8 -4484807029008447544 
8 c1c2c3c4c5c6c7c8 -4484807029008447544
4 c5c6c7c8 -976828472 
2 ffffc7c8 -14392 
1 ffffffc8 -56
2 ffffffc8 -56
4 ffffffc8 -56
8 ffffffffffffffc8 -56
8 ffffffffffffffc8 -56
4 80000000 -2147483648
4 c0000000 -1073741824 
4 ffffffff -1 
4 ffffffff -1 
8 c1c2c3c4c5c6c7c8 13961937044701104072 
8 c1c2c3c4c5c6c7c8 13961937044701104072
4 c5c6c7c8 3318138824
2 c7c8 51144
1 c8 200
2 c8 200
4 c8 200
8 c8 200
8 c8 200
16 3.141592653589793238512808959406186204432742670178413391113281250000000000000000 
 8 3.141592653589793115997963468544185161590576171875000000000000000000000000000000 
 4 3.141592741012573242187500000000000000000000000000000000000000000000000000000000

A home-brewed mini-printf (variadic functions, indirect recursion)

#include <stdio.h>
#include <stdarg.h>
 
int vrprintf(const char *format, va_list ap);
 
static int putcx(int c) {
    if (c!=0) {
        putchar(c);
        return 1;
    } else
        return 0;
}
 
static char backchar[128] = {
        [0 ... 127] = 0,
        ['a'] = '\a',
        ['b'] = '\b',
        ['f'] = '\f',
        ['n'] = '\n',
        ['r'] = '\r',
        ['t'] = '\t',
        ['v'] = '\v',
        ['\\'] = '\\', 
        ['\''] = '\'', 
        ['"'] = '"',
        ['?'] = '?',
};
 
static int put_backslash(char escapeChar) {
    return putcx(backchar[escapeChar & 0x7f]);
}
 
static int rvrp_int(int val) {
    if (val == 0)
        return 0;
    else  
        return rvrp_int(val / 10) + putcx('0' + val % 10);
}
 
static int vrp_int(int val) {
    if (val != 0) {
        if (val < 0)
            return putcx('-') + rvrp_int(-val);
        else
            return rvrp_int(val);
    } else
        return putcx('0');
}
 
static int vrp_string(char *s) {
    switch (*s) {
        case 0:
            return 0;
        case '\\':
            
            return put_backslash(*(s+1)) ? vrp_string(s + 2) + 1 : 0;
        default:
            return putcx(*s) + vrp_string(s + 1);
    }
}
 
static int vrp_percent(const char *format, va_list ap) {
    switch (*format) {
        case 0:
            return 0;
        case '%':
            return putcx(*format) + vrprintf(format + 1, ap);
        case 'd':
            return vrp_int(va_arg(ap, int)) + vrprintf(format + 1, ap);
        case 's':
            return vrp_string(va_arg(ap, char *)) + vrprintf(format + 1, ap);;
        default:
            printf("ERROR\n");
            return 0;
    }
}
 
int vrprintf(const char *format, va_list ap) {
    switch (*format) {
        case 0:
            return 0;
        case '%':
            return vrp_percent(format + 1, ap);
        case '\\':
            return put_backslash(*(format+1)) ? vrprintf(format + 2, ap) + 1 : 0;
        default:
            return putcx(*format) + vrprintf(format + 1, ap);
    }
}
 

int rprintf(const char *format, ...) {
    int rval;
    va_list ap;
    va_start (ap, format);
    rval = vrprintf(format, ap);
    va_end(ap);
    return rval;
}
 
int main() {
    int v;
    v = rprintf("hello world\n");
    printf("%d\n", v);
    v = printf("hello world\n");
    printf("%d\n", v);
    v = rprintf("hello world %d\n", 10);
    printf("%d\n", v);
    v = printf("hello world %d\n", 10);
    printf("%d\n", v);
    v = rprintf("hello world %s %d\n", "piripicchio", 42);
    printf("%d\n", v);
    v = printf("hello world %s %d\n", "piripicchio", 42);
    printf("%d\n", v);
    v = rprintf("hello world %% \"%s\" %d\n", "piripicchio\tbackslash", 42);
    printf("%d\n", v);
    v = printf("hello world %% \"%s\" %d\n", "piripicchio\tbackslash", 42);
    printf("%d\n", v);
    v = rprintf("%%\n");
    printf("%d\n", v);
    v = printf("%%\n");
    printf("%d\n", v);
}

tokenize (variable length arrays, printf %.*)

#include <stdio.h>
#include <string.h>

const char *sep=" \t\n";

void tokenize(const char *s) {
  const char *t;
  for ( ; *s != 0; s = t) {
    for ( ; strchr(sep, *s) ; s++)
      ;
    if (*s == 0)
      break;
    for (t = s; ! strchr(sep, *t); t++)
      ;
    size_t len = t - s;
    char token[len + 1];
    sprintf(token, "%.*s", len, s);
    printf("TOKEN='%s'\n", token);
  }
}

int main(int argc, char *argv[]) {
  for ( ; argc > 1 ; argc--, argv++) {
    tokenize(argv[1]);
  }
}