Esercizi di "lettura" programmi in C

From Sistemi Operativi
Revision as of 11:08, 10 October 2022 by Renzo (talk | contribs) (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...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

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];
  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

(compiler extension)

#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);
}

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;
}

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 page 33.

#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]);
  }
}