A P P E N D I X  D

Supported Features of C99

This appendix lists the supported features of the ISO/IEC 9899:1999, Programming Language - C standard. This appendix also provides discussions and examples for some of these supported features. For more information on the supported features not discussed in this appendix, see http://forte.sun.com/s1scc/index.html .

The -xc99 flag controls compiler recognition of the implemented features. For more information on the syntax of -xc99, see -xc99[=o].



Note - Though the compiler defaults to supporting the features of C99 listed below, standard headers provided by Solaris software in /usr/include do not yet conform with the 1999 ISO/IEC C standard. If error messages are encountered, try using -xc99=%none to obtain the 1990 ISO/IEC C standard behavior for these headers.



This release supports a partial implementation of _Complex. You must link with -lcplxsupp on the Solaris 7 operating environment, the Solaris 8 operating environment, and the Solaris 9 operating environment.


D.1 Idempotent Qualifiers

6.7.3 Type qualifiers:

If the same qualifier appears more than once in the same specifier-qualifier-list, either directly or through one or more typedefs, the behavior is the same as when the type qualifier appears only once.

In C90, the following code would cause an error:

%example cat test.c
 
const const int a;
 
int main(void) {
  return(0);
} 
 
%example cc -xc99=%none test.c
"test.c", line 1: invalid type combination

However, with C99, the C compiler accepts multiple qualifiers.

%example cc -xc99 test.c
%example


D.2 _Pragma

A unary operator expression of the form: _Pragma ( string-literal ) is processed as follows:

The resulting sequence of preprocessing tokens are processed as if they were the preprocessor tokens in a pragma directive.

The original four preprocessing tokens in the unary operator expression are removed.

_Pragma offers an advantage over #pragma in that _Pragma can be used in a macro definition.

_Pragma("string") behaves exactly the same as #pragma string. Consider the following example. First, the example's source code is listed and then the example's source is listed after the preprocessor has made it's pass.

example% cat test.c
 
#include <omp.h>
#include <stdio.h>
 
#define Pragma(x) _Pragma(#x)
#define OMP(directive) Pragma(omp directive)
 
void main() 
{
  omp_set_dynamic(0);
  omp_set_num_threads(2);
  OMP(parallel)
  {
  printf("Hello!\n");
  }
}
 
example% cc test.c -P -xopenmp -x03
example% cat test.i 

Here's the source after the preprocessor has finished.

void main() 
{
  omp_set_dynamic(0);
  omp_set_num_threads(2);
  # pragma omp parallel
  {
    printf("Hellow!\n");
  }
}
 
example% cc test.c -xopenmp -->
example% ./a.out
Hello!
Hello!
example%


D.3 Mixed Declarations and Code

6.8.2 Compound statement

The C compiler now accepts mixing type declarations with executable code as shown by the following example:

#include <stdio.h>
 
int main(void){
  int num1 = 3;
  printf("%d\n", num1);
 
  int num2 = 10;
  printf("%d\n", num2);
  return(0);
}


D.4 Static and Other Type Qualifiers Allowed in Array Declarators

6.7.5.2 Array declarator:

The keyword static can now appear in the Array declarator of a parameter in a function declarator to indicate that the compiler can assume at least that many elements will be passed to the function being declared. Allows the optimizer to make assumptions about which it otherwise could not determine.

The C compiler adjusts array parameters into pointers therefore void foo(int a[]) is the same as void foo(int *a).

If you specify type qualifiers such as void foo(int * restrict a);, the C compiler expresses it with array syntax void foo(int a[restrict]); which is essentially the same as declaring a restricted pointer.

The C compiler also uses a static qualifier to preserve information about the array size. For example, if you specify void foo(int a[10]) the compiler still expresses it as void foo(int *a). Use a static qualifier as follows, void foo(int a[static 10]), to let the compiler know that pointer a is not NULL and that it provides access to an integer array of at least ten elements.


D.5 Flexible Array Members

6.7.2.1 Structure and union specifiers

Also known as the "struct hack". Allows the last member of a struct to be an array of zero length, such as int foo[]; Such a struct is commonly used as the header to access malloced memory.

For example, in this structure, struct s { int n; double d[]; } S;, the array, d, is an incomplete array type. The C compiler does not count any memory offset for this member of S. In other words, sizeof(struct s) is the same as the offset of S.n.

d can be used like any, ordinary, array-member. S.d[10] = 0;.

Without the C compiler's support for an incomplete array type, you would define and declare a structure as the following example, called DynamicDouble, shows:

typedef struct { int n; double d[1]; ) DynamicDouble;

Note that the array d is not an incomplete array type and is declared with one member.

Next, you declare a pointer dd and allocate memory thus:

DynamicDouble *dd = malloc(sizeof(DynamicDouble)+(actual_size-1)*sizeof(double));

You then store the size of the offset in S.n thus:

dd->n = actual_size;

Because the compiler supports incomplete array types, you can achieve the same result without declaring the array with one member:

typedef struct { int n; double d[]; } DynamicDouble;

You now declare a pointer dd and allocate memory as before, except that it is no longer necessary to subtract one from actual_size:

DynamicDouble *dd = malloc (sizeof(DynamicDouble) + (actual_size)*sizeof(double)); 

The offset is stored, as before, in S.n thus:

dd->n = actual_size;


D.6 Declarations Using Implicit int

6.7.2 Type specifiers:

At least one type specifier shall be given in the declaration specifiers in each declaration.

The C compiler now issues warnings on any implicit int declaration as in the following example:

example% more test.c
volatile i;
const foo() 
{
  return i;
}
example% cc test.c
  "test.c", line 1: warning: no explicit type given
  "test.c", line 3: warning: no explicit type given
example%


D.7 Disallowed Implicit int and Implicit Function Declarations

Implicit declarations are no longer allowed in the 1999 C standard as they were in the 1990 C standard. Previous versions of the C compiler issued warning messages about implicit definitions only with -v (verbose). These messages and new additional warnings about implicit definitions, are now issued whenever identifiers are implicitly defined as int or functions.

This change is very likely to be noticed by nearly all users of this compiler because it can lead to a large number of warning messages. Common causes include a failure to include the appropriate system header files that declare functions being used, like printf which needs <stdio.h> included. The 1990 C standard behavior of accepting implicit declarations silently can be restored using -xc99=%none.

The C compiler now generates a warning for an implicit function declaration:

example% cat test.c
void main() 
{
  printf("Hello, world!\n");
}
example% cc test.c
"test.c", line 3: warning: implicit function declaration: printf
example%


D.8 Declaration in for-Loop Statement

6.8.5 Iteration statements

The C compiler now accepts a type declaration as the first expression in a for loop-statement:

for (int i=0; i<10; i++){ //loop body };

The scope of any variable declared in the initialization statement of the for loop is the entire loop (including controlling and iteration expressions).


D.9 C99 Keywords

6.4.1 Keywords

The C99 standard introduces the following new keywords. The compiler issues a warning if you use these keywords as identifiers while compiling with -xc99=%none. Without -xc99=%none the compiler issues a warning or error messages for use of these keywords as identifiers depending on the context.

D.9.1 Using the restrict Keyword

An object that is accessed through a restrict qualified pointer requires that all accesses to that object use, directly or indirectly, the value of that particular restrict qualified pointer. Any access to the object through any other means may result in undefined behavior. The intended use of the restrict qualifier is to allow the compiler to make assumptions that promote optimizations.

See Section 3.8.2, Restricted Pointers for examples and an explanation on how to use the restrict qualifier effectively.


D.10 __func__ Support

6.4.2.2 Predefined identifiers

The compiler provides support for the predefined identifier __func__. __func__ is defined as an array of chars which contains the name of the current function in which __func__ appears.


D.11 Macros With a Variable Number of Arguments

6.10.3 Macro replacement

The C compiler accepts #define preprocessor directives of the following form:

#define identifier (...) replacement_list
#define identifier (identifier_list, ...) replacement_list

If the identifier_list in the macro definition ends with an ellipses, it means that there will be more arguments in the invocation than there are parameters in the macro definition, excluding the ellipsis. Otherwise, the number of parameters in the macro definition, including those arguments which consist of no preprocessing tokens, matches the number of arguments. Use the identifier __VA_ARGS__ in the replacement list of a #define preprocessing directive which uses the ellipsis notation in its arguments. The following example demonstrates the variable argument list macro facilities.

#define debug(...) fprintf(stderr, __VA_ARGS__)
#define showlist(...) puts(#__VA_ARGS__)
#define report(test, ...) ((test)?puts(#test):\
						printf(__VA_ARGS__))
debug("Flag");
debug("X = %d\n",x);
showlist(The first, second, and third items.);
report(x>y, "x is %d but y is %d", x, y);

which results in the following:

fprintf(stderr, "Flag");
fprintf(stderr, "X = %d\n", x);
puts("The first, second, and third items.");
((x>y)?puts("x>y"):printf("x is %d but y is %d", x, y));


D.12 Variable Length Arrays (VLA):

6.7.5.2 Array declarators

VLAs are allocated on the stack as if by calling the alloca function. Their lifetime, regardless of their scope, is the same as any data allocated on the stack by calling alloca; until the function returns. The space allocated is freed when the stack is released upon returning from the function in which the VLA is allocated.

Not all constraints are yet enforced for variable length arrays. Constraint violations lead to undefined results.

#include <stdio.h>
void foo(int);
 
int main(void) { 
  foo(4);
  return(0);
}
 
void foo (int n) {
  int i;
  int a[n];
  for (i = 0; i < n; i++)
    a[i] = n-i;
  for (i = n-1; i >= 0; i--)
    printf("a[%d] = %d\n", i, a[i]);
}
 
example% cc test.c
example% a.out
a[3] = 1
a[2] = 2
a[1] = 3
a[0] = 4


D.13 inline Specifier for Static Functions

6.7.4 Function specifiers

The C99 function-specifier inline has been added. inline is fully functional for functions with internal linkage. For functions defined with external linkage use of the inline function-specifier creates an inline definition only, no external definition of the function is created. Thus pointers to inline functions with external linkage are unique to each translation unit and will not compare equal.


D.14 Commenting Code With //

6.4.9 Comments

The characters // introduce a comment that includes all multibyte characters up to, but not including, the next new-line character except when the // characters appear within a character constant, a string literal, or a comment.