Robert Elder Software Inc.
  • Home
  • Store
  • Blog
  • Contact
  • Home
  • Store
  • Blog
  • Contact
  • #linux
  • |
  • #commandline
  • |
  • #softwareengineering
  • |
  • #embeddedsystems
  • |
  • #compilers
  • ...
  • View All >>

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
How to Get Fired Using Switch Statements & Statement Expressions
Published 2016-10-27
C Programming Fridge Magnets
$40.00 CAD
C Programming Fridge Magnets
Should I use Signed or Unsigned Ints In C? (Part 1)
Should I use Signed or Unsigned Ints In C? (Part 1)
Published 2015-07-27
The Jim Roskind C and C++ Grammars
The Jim Roskind C and C++ Grammars
Published 2018-02-15
7 Scandalous Weird Old Things About The C Preprocessor
7 Scandalous Weird Old Things About The C Preprocessor
Published 2015-09-20
GCC's Signed Overflow Trapping With -ftrapv Silently Doesn't Work
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)
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
Building A C Compiler Type System - Part 1: The Formidable Declarator
Published 2016-07-07
Join My Mailing List
Privacy Policy
Why Bother Subscribing?
  • Free Software/Engineering Content. I publish all of my educational content publicly for free so everybody can make use of it.  Why bother signing up for a paid 'course', when you can just sign up for this email list?
  • Read about cool new products that I'm building. How do I make money? Glad you asked!  You'll get some emails with examples of things that I sell.  You might even get some business ideas of your own :)
  • People actually like this email list. I know that sounds crazy, because who actually subscribes to email lists these days, right?  Well, some do, and if you end up not liking it, I give you permission to unsubscribe and mark it as spam.
© 2025 Robert Elder Software Inc.
SocialSocialSocialSocialSocialSocialSocial
Privacy Policy      Store Policies      Terms of Use