Strange Corners of C
2015-05-25 - By Robert Elder
In my attempts to learn the C programming language well enough to write my own C compiler, I've encountered some very interesting examples of C syntax that you generally don't see every day. All of these examples you'll see here will compile without warnings or errors even with very strict compiler flags in gcc and clang (gcc -Wall -ansi -pedantic -std=c89 main.c). Here are a few of those examples together in one program:
#include <stdio.h>
/*  You can use this structure to access floats by field and by normal 'float' type 
    Note that the ordering of the bitfields must match the endianness of the host. 
    The example below will only work for IEEE 754 implementations of single-precision
    floats on little endian machines */
struct lol {
        /*  IEEE 754 Single Precision floating point accessor */
        union {
                /*  Access by single-precision floating point parts: */
                struct {
                        unsigned int /* fraction bits: */c:23, /* exponentbits: */b:8, /* sign bit: */a:1;
                } f;
                /*  Access float: */
                float g;
        } data;
};
/*  You can typedef a function declaration */
typedef unsigned int * koo(long);
/*  And declare function prototypes (but you can't define them using the typedef) */
koo loo;
/*  You can define a structure in a return type */
struct foo { int i; } function(void){
        struct foo boo = {0};
        return boo;
}
/*  What's going on with these functions?  */
/*  Nested function pointer return types of course.  */
int foo1(int);
int foo1(int foo1param){
/*  Function that takes an int and returns an int */
        return foo1param;
}
int (*foo2(void))(int i);
int (*foo2(void))(int i){
/*  Function that takes 0 parameters and returns a pointer to a function that
    takes an int and returns an int */
        return foo1;
}
int (*(*foo3(void))(void))(int i);
int (*(*foo3(void))(void))(int i){
/*  Function that takes 0 parameters and returns a pointer to a function that
    takes 0 parameters and returns a pointer to a function that takes an int
    and returns an int */
        return foo2;
}
int (*(*(*foo4(void))(void))(void))(int i);
int (*(*(*foo4(void))(void))(void))(int i){
/*  Function that takes 0 parameters and returns a pointer to a function that
    takes 0 parameters and returns a pointer to a function that takes 0
    parameters and returns a pointer to a function that takes an int and
    returns an int */
        return foo3;
}
int (*(*(*(*foo5(void))(void))(void))(void))(int i);
int (*(*(*(*foo5(void))(void))(void))(void))(int i){
/*  Function that takes 0 parameters and returns a pointer to a function that
    takes 0 parameters and returns a pointer to a function that takes 0
    parameters and returns a pointer to a function that takes 0 parameters
    and returns a pointer to a function that takes an int and returns an int */
        return foo4;
}
/*  **************************************  */
void do_f(void);
void do_f(void){
        /*  This is called duff's device and there are many great explanations online: 
            http://en.wikipedia.org/wiki/Duff%27s_device                             */
        /*  What does this do?  */
        unsigned int count = 22;
        unsigned int j = (count + 7) / 8;
        putchar('\n');
        switch(count % 8) {
                case 0: do{     putchar('0' + (int)j);
                case 7:         putchar('0' + (int)j);
                case 6:         putchar('0' + (int)j);
                case 5:         putchar('0' + (int)j);
                case 4:         putchar('0' + (int)j);
                case 3:         putchar('0' + (int)j);
                case 2:         putchar('0' + (int)j);
                case 1:         putchar('0' + (int)j);
                        } while(--j > 0);
        }
        putchar('\n');
}
/*  What does this line do?  */
/*  It declares one variable and two functions  */
/*  A function i that tkes no parameters and returns an unsigned int  */
/*  An unsigned int k initialized to 9  */
/*  A function g that takes no parameters and returns a pointer to an array
    of three unsigned integers  */
unsigned int i(void), k = 9, (*g(void))[3];
int main(void){
/*  This works because "Hello"[5] == 5["Hello"].*/
        char c = 3["Hello"];
/*
a[i] == *(      a        +  i   )  Here the type of a is 'const char [6]' and the type of i is 'int'
a[i] == *(const char [6] + int  )  These are the types corresponding to 'a' and 'i'.
        *(const char  *  + int  )  The type of a decays into 'const char *'
        *(int  +  const char  * )  Since addition is commutative, we can re-arrange freely
i[a] == *(int  +  const char  * )
*/
        int i = c;
        /*  What's the difference between these two? */
        int * j;
        int (* k);
        /*  There is no difference */
        /*  What's the difference between these two? */
        int * l[2];   /*  Array of two pointers to integers */
        int (* m)[2]; /*  Pointer to an array of two integers */
        int arr[2];
        struct lol p;
        arr[0] = 'a';
        arr[1] = 'b';
        j = &i;
        k = &i;
        l[0] = &i;
        m = &arr;
        do_f();
        p.data.f.a = 1;
        p.data.f.b = 3 + 127;  /* Bias of 127 */
        p.data.f.c = 2;
        printf("%.100f\n",p.data.g);
        p.data.f.a = 0;
        p.data.f.b = 0 + 127;
        p.data.f.c = 7;
        printf("%.100f\n",p.data.g);
        printf("%c %c %c %c %c %c %c\n", foo5()()()()('a'), c, i, *j, *k, *l[0], (*m)[0]);
        return 0;
}
If you found this interesting, you might want to check out my C compiler.
| How to Get Fired Using Switch Statements & Statement Expressions Published 2016-10-27 | Buy Now -> | Should I use Signed or Unsigned Ints In C? (Part 1) Published 2015-07-27 | The Jim Roskind C and C++ Grammars Published 2018-02-15 | 
| 7 Scandalous Weird Old Things About The C Preprocessor Published 2015-09-20 | GCC's Signed Overflow Trapping With -ftrapv Silently Doesn't Work Published 2016-05-25 | Should I use Signed or Unsigned Ints In C? (Part 2) Published 2015-08-16 | Building A C Compiler Type System - Part 1: The Formidable Declarator Published 2016-07-07 | 
| Join My Mailing List Privacy Policy | Why Bother Subscribing? 
 |