1.4.1. Language features

The C99 standard introduces several new language features of interest to programmers, including:

A selection of new language features of C99 that might be of particular interest are discussed in the following sections.

// comments

You can use // to indicate the start of a one-line comment, just as in C++. See // comments in the Compiler Reference Guide for more information.

Compound literals

ISO C99 supports compound literals. A compound literal looks like a cast followed by an initializer. Its value is an object of the type specified in the cast, containing the elements specified in the initializer. It is an lvalue. For example:

int y[] = (int []) {1, 2, 3}; 
int z[] = (int [3]) {1};

Designated initializers

In C90, there is no way to initialize specific members of arrays, structures, or unions. C99 supports the initialization of specific members of an array, structure, or union by either name or subscript through the use of designated initializers. For example:

typedef struct
{
    char *name;
    int rank;
} data;

data vars[10] = { [0].name = "foo", [0].rank = 1,
                  [1].name = "bar", [1].rank = 2,
                  [2].name = "baz", 
                  [3].name = "gazonk" };

Members of an aggregate that are not explicitly initialized are initialized to zero by default.

Hex floats

C99 supports floating-point numbers that can be written in hexadecimal format. For example:

float hex_floats(void)
{
    return 0x1.fp3; // 1 15/16 * 2^3
}

In hexadecimal format the exponent is a decimal number that indicates the power of two by which the significant part is multiplied. Therefore 0x1.fp3 = 1.9375 * 8 = 1.55e1.

Flexible array members

In a struct with more than one member, the last member of the struct can have incomplete array type. Such a member is called a flexible array member of the struct.

Note

When a struct has a flexible array member, the entire struct itself has incomplete type.

Flexible array members enable you to mimic dynamic type specification in C in the sense that you can defer the specification of the array size to runtime. For example:

extern const int n;

typedef struct
{
    int len;
    char p[];
} str;

void foo(void){
    size_t str_size = sizeof(str);  // equivalent to offsetoff(str, p)
    str *s = malloc(str_size + (sizeof(char) * n));
}

The object s can be considered as having the declaration:

extern const int n;

struct
{
    int len;
    char p[n];
} s;

__func__ predefined identifier

The __func__ predefined identifier provides a means of obtaining the name of the current function. For example, the function:

void foo(void)
{
    printf("This function is called '%s'.\n", __func__);
}

prints:

This function is called 'foo'.

inline functions

The C99 keyword inline hints to the compiler that invocations of a function qualified with inline are to be expanded inline. For example:

inline int max(int a, int b)
{
    return (a > b) ? a : b;    
}

The compiler inlines a function qualified with inline only if it is reasonable to do so. It is free to ignore the hint if inlining the function adversely affects performance. See Inlining for more information.

Note

The semantics of inline in C99 are different to the semantics of inline in Standard C++.

long long data type

C99 supports the integral data type long long. This type is exactly 64 bits wide in RVCT. For example:

long long int j = 25902068371200;                // length of light day, meters
unsigned long long int i = 94607304725808000ULL; // length of light year, meters

See long long in the Compiler Reference Guide for more information.

Macros with a variable number of arguments

You can declare a macro in C99 that accepts a variable number of arguments. The syntax for defining such a macro is similar to that of a function. For example:

#define debug(format, ...) fprintf (stderr, format, __VA_ARGS__)
void Variadic_Macros_0()
{
    debug ("a test string is printed out along with %x %x %x\n", 12, 14, 20);
}

Mixed declarations and code

C99 enables you to mix declarations and code within compound statements, just as in C++. For example:

void foo(float i)
{
    i = (i > 0) ? -i : i;
    float j = sqrt(i);    // illegal in C90
}

New block scopes for selection and iteration statements

In a for loop, the first expression may be a declaration, just as in C++. The scope of the declaration extends to the body of the loop only. For example:

extern int max;

for (int n = max - 1; n >= 0; n--)
{
    // body of loop
}

is equivalent to:

extern int max;

{
    int n = max - 1;
    for (; n >= 0; n--)
    {
        // body of loop    }
}

Note

Unlike in C++, you cannot introduce new declarations in a for-test, if-test or switch-expression.

_Pragma preprocessing operator

C90 does not permit a #pragma directive to be produced as the result of a macro expansion. The C99 _Pragma operator enables you to embed a preprocessor macro in a pragma directive. For example:

# define RWDATA(X) PRAGMA(arm section rwdata=#X)
# define PRAGMA(X) _Pragma(#X)

RWDATA(foo)  // same as #pragma arm section rwdata="foo"

int y = 1;   // y is placed in section "foo"

Restricted pointers

The C99 keyword restrict enables you to ensure that different object pointer types and function parameter arrays do not point to overlapping regions of memory. This enables the compiler to perform optimizations that might otherwise be prevented because of possible aliasing.

In the following example, pointer a does not, and cannot, point to the same region of memory as pointer b:

void copy_array(int n, int *restrict a, int *restrict b)
{
    while (n-- > 0)
        *a++ = *b++;
}

void test(void)
{
    extern int array[100];

    copy_array(50, array + 50, array);    // valid
    copy_array(50, array + 1, array);     // undefined behavior
}

Pointers qualified with restrict can however point to different arrays, or to different regions within an array.

Copyright © 2002-2007 ARM Limited. All rights reserved.ARM DUI 0205H
Non-Confidential