Movatterモバイル変換


[0]ホーム

URL:


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 thealloca 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;};{// old spanstruct fops f1 = { open:0, close:1, read:2};// new spanstruct 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.

// initializing an array of intint a[7] = { [5]=1, [2]=3,2};// resulting inint a[7] = {0,0,3,2,0,1,0};// initializing an array of structstruct {int x,y; } ar[4] = { [1].x=23, [3].y=34, [1].y=-1, [1].x=12};// resulting instruct {int x,y; } ar[4] = { {0,0}, {12,-1}, {0,0}, {0,34}};// interesting usagechar 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};// this is standardp1 = (struct point){1,3};// this is new// passing to the functionfoo( (struct point){10,11}, (struct point){1,2});// constructing an arraychar **sx = (char *[]){"Adam","Eva","Simon"};}

Inline functions

Yes, C has inline functions. Like in C++ prepend the function header with theinline 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 thecheck 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>pushebp<add+01>movebp,esp<add+03>movecx,DWORD PTR [ebp+8]<add+06>movDWORD PTR [ecx],0x0<add+12>moveax,0x0<add+17>movedx,0x0<add+22>incedx<add+23>inceax<add+24>cmpeax,0x9<add+27>jle<add+22><add+29>movDWORD 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 asvolatile 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(charrestrict *s1,charrestrict *s2,int n){while (n--)*s1++ = *s2++;}

Both functions copy one block of chars into another. Incopy2 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

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 filestdint.h. There are typedefined types like (where N is in { 8, 16, 32, 64})

Unsigned variants have prefix "u".

Be careful when usingprintf functions. Since you do not know which C type are behind these typedefs, you have to use predefined constants frominttypes.h. Constants starts withPRI followed by type character (one ofdiouxX), modificatorLEAST orFAST or nothing, and number of bits. For example, 32 bit fast integer would take the formPRIdFAST32.

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 filestdbool.h only typedefines_Bool as abool and defines constantsfalse as 0 andtrue as 1.

This is not C++bool!

Complex numbers

C has three complex types: {float,double,long double}_Complex. In the header filecomplex.h_Complex is typedefined tocomplex. Complex types may be not implemented in freestanding (without OS) implementations.


[8]ページ先頭

©2009-2025 Movatter.jp