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 |
$40.00 CAD |
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?
|