Lesser known C features

There are many C features which are lesser known even to experienced programmers.

Array of a variable size

Do not be confused with dynamic arrays. C99 supports arrays of variable length where the size is calculated at run-time while processing the array definition. This is a back-port from C++ and far better than the alloca function. Have a look at the example below. int fo( int i) { return i+ 1 ; } void f( int len, char s[ len][ fo( len+ 1 )* 2 ]) { for ( int i= 1 ; i< 10 ; i++) { char s1[ i+len]; ... } } It is not possible to skip the definition using break in switch statement.

Flexible array as a member of a structure

Arrays with unspecified size are used in structures to help addressing data past the structure end. struct s { int i; unsigned u; char end[]; }; There are several restrictions. The flexible array member must be the last element of the structure and the structure itself must be neither used in another structure definition nor as a member of an array.

Structure field addressing in definitions

In old C the fields of a structure have to be in fixed order during initialization. It is a well-known GNU extension that specifies structure fields with the label-like syntax. C99 has a new approach using the . operator. Although it looks strange, it has a hidden meaning (see below). struct fops { int open, read, write, close; }; { struct fops f1 = { open: 0 , close: 1 , read: 2 }; struct fops f2 = { .open= 0 , .close= 1 , .read= 2 } }; }

Array initialization

It is not very well known that an array initiator may jump in index like in the enumeration definition. int a[ 7 ] = { [ 5 ]= 1 , [ 2 ]= 3 , 2 }; int a[ 7 ] = { 0 , 0 , 3 , 2 , 0 , 1 , 0 }; struct { int x,y; } ar[ 4 ] = { [ 1 ].x= 23 , [ 3 ].y= 34 , [ 1 ].y= -1 , [ 1 ].x= 12 }; struct { int x,y; } ar[ 4 ] = { { 0 , 0 }, { 12 , -1 }, { 0 , 0 }, { 0 , 34 }}; char forbidden[ 256 ] = { [ 'a' ]= 1 , [ 'e' ]= 1 , [ 'i' ]= 1 , [ 'o' ]= 1 , [ 'u' ]= 1 }; Note that already initialized fields may be overwritten.

Compound literals

Compounds literals bring a new method of assigning to structures and passing structures as parameters. struct point { int x, y; }; void foo( struct point p1, struct point p2); { struct point p1 = { 2 , 4 }; p1 = ( struct point){ 1 , 3 }; foo( ( struct point){ 10 , 11 }, ( struct point){ 1 , 2 }); char **sx = ( char *[]){ "Adam" , "Eva" , "Simon" }; }

Inline functions

Yes, C has inline functions. Like in C++ prepend the function header with the inline keyword ( __inline__ in headers). Note that certain constructions may disallow the compiler to inline the function. Especially constructions implemented on stack like variadic parameters, alloca or variable sized arrays.

Volatile type qualifier

Have a look at the example below - there are two functions each executed in a separate thread with the same pointer as a parameter. Do you think that the check function must terminate? void add( int *i) { while ( 1 ) { *i = 0 ; for ( int a= 0 ; a< 10 ; a++) (*i)++; } } void check( int *i) { while (*i == 5 ) ; } No, it doesn't have to. The incrementation may by optimized. Below is a disassembled code produced by GCC -O1: <add+ 00 > push ebp <add+ 01 > mov ebp,esp <add+ 03 > mov ecx, DWORD PTR [ebp+ 8 ] <add+ 06 > mov DWORD PTR [ecx], 0x0 <add+ 12 > mov eax, 0x0 <add+ 17 > mov edx, 0x0 <add+ 22 > inc edx <add+ 23 > inc eax <add+ 24 > cmp eax, 0x9 <add+ 27 > jle <add+ 22 > <add+ 29 > mov DWORD PTR [ecx],edx <add+ 31 > jmp <add+ 6 > As we can see, *i has been replaced by the edx register, which is written only at the beginning and at the end of the cycle. The value of *i switches between 0 and 10, and never becomes 5. Marking the pointer as volatile will solve the problem. The semantics is that a volatile object may change its value outside the scope of local execution and thus every read and write access has to be processed immediately without any optimizations. Focus on this problem when you observe different behavior across different optimization levels. It is not guaranteed that a read or write access even on volatile objects are atomic.

Restricted pointers

The freedom of pointers in C leads sometimes to slower code. The programmer can enable several optimizations by guarantying that objects referred by pointers do not overlap. void copy1( char *s1, char *s2, int n) { while (n--) *s1++ = *s2++; } void copy2( char restrict *s1, char restrict *s2, int n) { while (n--) *s1++ = *s2++; } Both functions copy one block of chars into another. In copy2 the compiler may use word addressing instructions to speedup the execution. But when blocks overlap the behavior is undefined.

Macros with variable number of parameters

The syntax is similar to functions. Parameters in ... are then addressed as __VA_ARGS__ (variable argument). #define myfunc( A, B, ...) do_something( 0, B, A, __VA_ARGS__);

Some predefined identifiers

__FILE__ expands to a string name of a current source file

expands to a string name of a current source file __func__ expands to a string name of a current function

expands to a string name of a current function __LINE__ is expanded to the line number. This can be overwritten with the #line preprocessor directive

is expanded to the line number. This can be overwritten with the preprocessor directive __DATE__ date of compilation

date of compilation __TIME__ time of compilation

time of compilation __STDC_VERSION__ is expanded to long int which represents the ISO norm (199901L as an example)

Trigraphs

This may looks like a joke, but it is not. All occurrences of sequences ??<, ??>, ??(, ??), ??=, ??/, ??!, ??', ??- in a source file are converted to one of characters { } [ ] # / | ^ ~. So don't be surprised... As an aside, tokens <: :> <% %> %: behave as [ ] { } # and ## (but the conversion is not performed in strings).

Types with defined size

Have a look at the header file stdint.h . There are typedefined types like (where N is in { 8, 16, 32, 64}) intN_t - signed integers with exactly specified width

- signed integers with exactly specified width int_leastN_t - signed integers with a width of at least N

- signed integers with a width of at least N int_fastestN_t - fastest signed integers with a width of at least N Unsigned variants have prefix "u". Be careful when using printf functions. Since you do not know which C type are behind these typedefs, you have to use predefined constants from inttypes.h . Constants starts with PRI followed by type character (one of diouxX ), modificator LEAST or FAST or nothing, and number of bits. For example, 32 bit fast integer would take the form PRIdFAST32 .

Boolean type

C still does not have a boolean type, but reserves an integer type _Bool big enough to store 0 and 1. The header file stdbool.h only typedefines _Bool as a bool and defines constants false as 0 and true as 1. This is not C++ bool !

Complex numbers