Tech Talk About C99
Comeau C99 FAQ

Copyright © 2001-2013 Comeau Computing. All rights reserved. The intent of this page is to address questions about C99. C99 is a new revision to Standard C, and folks may not be familiar with all parts of it yet. Note that in its current form, most parts of this FAQ are essentially just an executive summary. This means that some additions and changes are still necessary. As such, this is a live web page, so we'll be adding completely new discussions as appropriate, so stop by from time to time. Clearly then, this web page is under construction, (Version 1.3, July, 2013), so if you see something not right, please email us about it.

As well, you may also want to take a look at our other Other FAQs, the Comeau C++ and C FAQ and the Comeau Templates FAQ.

Here's the current topics:

  1. What book do you recommend?
  2. Where is the FAQ for the various C and C++ newsgroups?
  3. Can I really get the C++ Standard electronically for $18?
  4. Can I get Standard C electronically too?
  5. What Are Designated initializers?
  6. What Are Compound Literals?
  7. What Are Variable Length Arrays?
  8. What Are Flexible Array Members?
  9. What Are _Bool and bool?
  10. What Are static array parameters?
  11. What Is __func__?
  12. What New Keywords are in C99?
  13. What is restrict?
  14. What is long long?
  15. What is inline?
  16. What is __STDC_VERSION__?
  17. What are the STDC pragma's?
  18. What are variadic macros?
  19. What is __VA_ARGS__?
  20. What are complex numbers?
  21. What are for loop intializers?
  22. How can I mix declarations with code?
  23. Must main return a value?
  24. What are // comments?
  25. What are universal characters?
  26. What are UCNs?
  27. What is va_copy?
  28. What are hex floating point constants?
  29. What Is _Pragma?
  30. Do you have a question to add??

What book do you recommend?

We don't recommend a book. It's naive to expect that one book could be so encompassing as to satisfy everybody and every topic. Therefore, we suggest that you get a few. What you should do is to check out our literature suggestions at as most of these books have withstood the test of time. Take the list with you to your favorite online or local technical bookstore. Take your time -- maybe an hour or more -- and browse the books for what looks right for you.

Note that we've broken our list down into categories, consider getting one or two from each category. Some you should get as references, others you should get to read from cover to cover.

Note that often there is a problem between technical accuracy and readability. You may have a very readable book that's telling you wrong things, or avoiding fundamentals or insights, but that's won't get you anywhere to be reading the wrong things albeit easily. The converse is a very accurate book that is not as easy to read. There is a price to pay either way, but generally you're better off with the technically correct text. We believe this is so for the short and long term. And in general, please make an effort to avoid product oriented books, or books with titles that just make things sound like everything will just be so great.

Categorically, we have not been satisfied with online tutorials (this does not mean that there are no good ones, just that we have not seen it yet). If you know of one that's excellent, don't hesitate to email us about it.

Back to Top  Back to Comeau Home

Where is the FAQ for the various C and C++ newsgroups?

Welcome to comp.lang.c++
The Comeau C++ and C FAQ
This document (The Comeau C++ TEMPLATES FAQ)
The Comeau C99 FAQ

In general, if you need a FAQ, check out

Back to Top  Back to Comeau Home

Can I really get the C++ Standard electronically for $18?
Can I get Standard C electronically too??

Yes, an electronic version of Standard C++ can be downloaded from ANSI for $18. For details on getting Standard C++, please refer to our discussion at

The latest revision of Standard C, so-called C99, is also available electronically too from ANSI. ANSI C89 or ISO C90 is still currently available but only in paper form. For instance, Global Engineering Documents was carrying C89 (X3.159). Once at that link, click US, enter "x3.159" in the document number (NOT the document title) search box, and that'll get you the latest info from Global on this paper document (last we checked it was US$148).

Back to Top  Back to Comeau Home

What Are Designated Initializers?

C99's designated initializers allow you to specifically initialize array elements and struct and union members. Consider:
struct xyz { int a; int b; int c[99]; };
// DI allow for that members can be named in initializer lists
// Note that member c is "zero'd" since it is not uttered in the init list
struct xyz AnXyz = { .b = 99, .a = -99 };
struct xyz AnXyz2 = { .b = 99 };

// DI's ok for array objects too
struct xyz AnXyz3 = { .c[2] = 44 };
int array[99] = { [33] = 33, [66] = 66 };
struct xyz AnXyz3b[] = { [5].c[2] = 44 };

struct abc { int d; struct xyz xyzmem; };
// DIs ok for subobject too
struct abc AnAbc = { .d = 11, .xyzmem.b = 33 };

// "weird" stuff too: take last DI, but eval all
// Look: member b done twice, last one "wins"
struct abc AnAbc2 = { .d = 11, .d = 22 };
int foo() { /* Computing Something... */ return 0; }
void bar()
    // Function necessary because foo() is not constant
    struct abc AnAbc3 = { foo(), .d = 22 };

int main()
    // unions ok too
    union U { int intmem; float floatmem; };
    union U u = { .floatmem = 99.99 };
    union U u2 = { .intmem = AnXyz2.b + 99 };
    return 0;
Back to Top  Back to Comeau Home

What Are Compound Literals?

// Compound literals avoid needing to create "funny named" object that
// might otherwise serve no other purpose but to be pointed to, etc.
// Some argue they are similar in nature to C++ construct calls.
// Compound literals are composed with a cast-like-kinda construct
// with a brace'd initializer to create unnamed array's.

int foo() { return 99; }

struct xyz { int i; int j; };
void bar(struct xyz dummy_arg) { }
void baz(struct xyz* dummy_arg) { }

// Initializers for the literals are required to be constant if in file scope
// Unnamed array is static if in file scope
int *p = (int []){ 1, 2 }; // p points to unnamed array of int[2]

int main()
    // non-constant initializers ok in enclosing block
    // unnamed array is auto here
    // foo() only done once
    int *p2 = (int []){ 1, foo() }; // ok

    (int []){ 1, 2 } = 99; // Error
    *(int []){ 1, 2 } = 99; // Ok, but yuck

    // Note the literal need not always just be an array
    p = &(int){ 1 }; // ok, but be careful

    // const compound literals need not be distinct
    const int *cix = (const int []){ 1, 2 };
    const int *ciy = (const int []){ 1, 2 }; // Same literal?

    // String literals do not have const in C. This alternative
    // might help in some cases (perhaps wrapped in a macro??):
    const char *ccp = (const char []){ "Comeau C/C++" };

    // Pass a compound literal to a function
    bar((struct xyz){ 123, 456 });
    // Combo'd with DI's from above:
    bar((struct xyz){ .i = 123, .j = 456 });

    // Pass addr of literals:
    baz(&(struct xyz){ 456, 789 });
Back to Top  Back to Comeau Home

What Are Variable Length Arrays?

#include <stdio.h>
#include <stdlib.h>
void funcWithVLA(int n)
    // Note that during the lifetime of a vla, its size does not change
    int vla[n];
    // sizeof eval'd at run-time not compile-time
    printf("%d\n", sizeof(vla)); // sizeof(int) * n
// Use * only in prototype, not def
// * indicates unspecified dimension
void funcTakingVLA(int size, int a[*]);

int Global = 99; // boo hiss
int GlobalVLA[Global]; // Error: VLA can't be extern
                       // extern's need constant for dimension

int main()
    int n = 99;
    int m = 999;
    extern int externVla[n]; // Error: VLA still can't be extern
    static int staticVla[n]; // Error: VLA can't be static either
    static int (*p)[n]; // ok: p has block scope and is *ptr* to a VLA
    int unknownSize[*]; // Error: VLA with unspecified bounds
                        // only allowed in function prototype scope
    struct blah {
        int vlamember[n]; // Error: struct members can't be VLAs

    // Eval n at runtime, therefore autoVLA is a VLA
    int autoVLA[n]; // ok
    int twoD[n][m]; // ok: 2d array, and so on

    int randVla[rand()]; // :)  size expression not constant, watch out for 0

    n = -99;
    int negVla[n]; // Error: size shall evaluate > 0
                   // This will normally be a runtime thing, not compile time

    // n eval'd here, not when VlaTD used
    typedef int VlaTD[n]; // ok: has block scope
    VlaTD  someid; // ok
    funcTakingVLA(n, autoVLA);

    // Remember, const is readonly in C, not as constant'y as in C++
    const int dimension = 99;
    int StillAVLA[dimension]; // Therefore, this is a VLA

    // VLA in for loop just fine:
    for(int VLAInForLoop[dimension], i = 0; i < dimension; i++) {
        // ...
        // code apparently using VLAInForLoop
        // ...
void funcTakingVLA(int size, int a[size])
Back to Top  Back to Comeau Home

What Are Flexible Array Members?

Flexible array members allow incomplete array struct members without bounds. Consider:
#include <stdlib.h>
struct flex {
    int mem; // Flex array must have a named member
    int arrayWoBoundsSpecified[]; // Flex member must be last member
struct NotAflex {
    int a[]; // Error: Flex member must be last member
                    // Therefore incomplete type should be complete
    int mem;

int main()
   // "as if" len = offsetof(struct flex, arrayWoBoundsSpecified)
   size_t len = sizeof(struct flex); 

   // Flexible array members might be useful for reading record
   // from a comm line, or getting variable length information.
   // The struct object "containing" with the flex array cannot be
   // longer than actual underlying object being accessed.
   // These examples use malloc().  It shouldn't have to 
   // be limited to just that, but will be where it will be
   // used most
   // (Do examples with DIs and CLs??)

   struct flex *p = malloc(len + 100);
   // This tends to product a dynamic type.
   // That is it is now "as if":
   // struct {
   //     int mem;
   //     // Assuming sizeof(int) is 2, then 100 / sizeof(int) is 50
   //     int arrayWoBoundsSpecified[50];
   // };
   p->arrayWoBoundsSpecified[49]; // ok

   struct flex *p2 = malloc(len + 80);
   // This is now "as if":
   // struct {
   //     int mem;
   //     // Assuming sizeof(int) is 2, then 80 / sizeof(int) is 40
   //     int arrayWoBoundsSpecified[40];
   // };
   p2->arrayWoBoundsSpecified[39]; // ok

   struct flex *p3 = malloc(len + 3);
   // This is now "as if":
   // struct {
   //     int mem;
   //     // Assuming sizeof(int) is 2, then 3 / sizeof(int) is 1
   //     int arrayWoBoundsSpecified[1];
   // };
   p3->arrayWoBoundsSpecified[0]; // ok

   struct flex *p4 = malloc(len + 1);
   // This is now "as if":
   // struct {
   //     int mem;
   //     // Assuming sizeof(int) is 2, then 1 / sizeof(int) is 0
   //     // The bounds therefore becomes 1
   //     int arrayWoBoundsSpecified[1];
   // };
   //  Even though the bounds became 1, these are undefined
   p4->arrayWoBoundsSpecified[0]; // undefined behavior
   int *pi = &p4->arrayWoBoundsSpecified[1]; // undefined behavior

   struct flex *p5 = malloc(sizeof *p5 + X * sizeof(int)));
   // The previous examples used "nonsense constants" such as
   // 100, 80, etc for the sizes, so p5 is an example with
   // a more realistic form that the malloc would look like.
   // So, sizeof *p5, will give you the sizeof what p5 points to,
   // which is a struct flex, and then since arrayWoBoundsSpecified
   // is type int, we need X times the sizeof that, to get us a int[X].
   // Obviously you'll need to declare and provide/compute a value
   // for X.
Back to Top  Back to Comeau Home

What Are _Bool and bool?

C99 now supports a boolean type _Bool and also bool via <stdbool.h>. Consider:
#include <stdio.h>
int main()
    // _Bool can hold 0 or 1
    // _Bool is an unsigned integer type
    _Bool b = 1;
    struct xyz {
         _Bool mem : 1; // _Bool bitfields allowed

    printf("%d\n", b); // 1
    b = 0;
    printf("%d\n", b); // 0

    _Bool *pb = &b;
    // If the expression evaluates to 0, then it converts to _Bool as 0, else 1
    b = pb;
    printf("%d\n", b); // 1
    b = -1;
    printf("%d\n", b); // 1
    b = (pb == 0);
    printf("%d\n", b); // 0
    return 0;

// #define's bool, true, false, __bool_true_false_are_defined macros
// as _Bool, 1, 0, and 1 respectively
#include <stdbool.h>
void foo()
    int this = 99;
    int that = -99;
    bool b;
    if (this || that)
        b = true;
        b = false;
Back to Top  Back to Comeau Home

What Are static array parameters?

Here's an example of a static array parameter:
void foo(int array[static 99]);
(Better example needed.)
Back to Top  Back to Comeau Home

What Is __func__?

__func__, indicates the name of the current function, as a static const char[?]
#include <stdio.h>
int main()
    printf("%s\n", __func__); // output "main"
    return 0;
Because __func__ was uttered, then main is written by the compiler "as if":
int main()
    // This line implicitly added by the compiler:
    static const char __func__[] = "main";
    printf("%d\n", __func__);
Back to Top  Back to Comeau Home

What New Keywords are in C99?

New keywords include restrict, long long, and inline.
Back to Top  Back to Comeau Home

What is restrict?

Add words for restrict....
Back to Top  Back to Comeau Home

What is long long?

A 64-bit integral type is now available as long long type, and unsigned long long. Support is also available for ll, ull, LL, and ULL as long long constant suffixes (note that Ll or lL are not supported). Support for I/O includes a %lld format specification in the printf and scanf families.
Back to Top  Back to Comeau Home

What is inline?

C99 also has inline capability. Consider:
// SomeFile.c

static int internalId = 99;

// inline is a hint, not a requirement to honor.
// An external definition has not been provided for foo
// Other translation unit's don't find this definition
inline void foo()
    // External linkage inline function can't ref a modifiable static
    static int modifiable = 99; // Error
    // External linkage inline function can't reference internal linkage id's
    int i = internalId; // Error
extern inline void foo(); // ok, now an external definition provided

static inline int bar() { return 99; } // ok
inline int baz() { return 99; } // ok

inline void NotDefined(); // Error: Needs to be defined in this translation unit

int main()
    /* May or may not use inline definition */
    int i = baz(); // if inline'd, then "as if": int i = 99;
Back to Top  Back to Comeau Home

What is __STDC_VERSION__?

For C99 __STDC_VERSION__ is 199901L instead of C95's 199409L.
Back to Top  Back to Comeau Home

What are the STDC pragma's?

C99 provides some support for IEC 559 allowing some support for specifying some floating point traits. This is in the form of a #pragma STDC. Support for STDC pragmasinclude:
Back to Top  Back to Comeau Home

What are variadic macros?
What is __VA_ARGS__?

Support for Variadic macros is now available. Consider:
#include <stdio.h>

// In C89/90, you need multiple macros with "funny" names to do this.
// Anyway, in this example, the arguments passed (those represented
// by the ...) replace the __VA_ARGS__ when the substitution occurs.
#define DoLogFile(...) fprintf(stderr, __VA_ARGS__)

// Variadic macros also help out if you want to effectively
// pass one argument  that contains commas
#define MakeName(...)  #__VA_ARGS__

// Of course, the macro can also take other args, so long as
// the ... is last
#define output(FILEptr, ...) fprintf(FILEptr, __VA_ARGS__)

// This is not right, since this is NOT a variadic macro
#define mac(arg) foo(arg, __VA_ARGS__)

int main()
    int bound = 99;
    int current_index = 88;
    int linenumber = 77;

    DoLogFile("Detected array out of bounds\n");
    DoLogFile("Bound = %d, current index =%d\n", bound, current_index);
    DoLogFile("Missing semicolon on line %d\n", linenumber);
    output(stderr, "Detected array out of bounds\n");

    char *p;
    p = MakeName(Mary);
    p = MakeName(Doe, John);
    p = MakeName(Martin Luther King, Jr.);
    // Combo two variadic macros
    DoLogFile("MakeName=%s\n", MakeName(This is a test, yes it is));
Back to Top  Back to Comeau Home

What are complex numbers?

Support for new floating types, complex and imaginary numbers, are now avasilable in C99: Here's some code:
// _Complex and _Imaginary are not required in freestanding implementations
int main()
    _Complex double cd = -99.99; // imaginary part is zero
    // either order ok
    double _Complex cda[] = {
        cd, -cd, cd, 1.23 * __I__
    double d = cda[1]; // imaginary part tossed

    _Imaginary double id = 99.99 * __I__;
    double x = id; // _Imaginary -> real --> 0
A new header is also available that brings in various macros:
#include <complex.h>
void foo()
    double complex c = 1 + 2.3 * I; // 1.0+2.3i
Various routines are also declared in <complex.h> including:
Back to Top  Back to Comeau Home

What are for loop intializers?

C++ style for loop initialization is also available in C99:
#include <stdio.h>
int main()
    for (register int i = 0; i < 99; i++)
	printf("%d\n", i);
    i = 0; // Error: i no longer in scope
Back to Top  Back to Comeau Home

How can I mix declarations with code?

Mixed declarations with code, ala C++, is now available in C99. For examples, see the code samples above, since many use this feature.
Back to Top  Back to Comeau Home

Must main return a value?

An implicit return 0; is now added by the compiler to main(). See the discussion beginning in our other FAQ about this.
Back to Top  Back to Comeau Home

What are // comments?

// style comments, ala C++, are now available in C99. A comment of this form starts with // and ends at the end of the line. Many of the code samples above use these "line" comments. In any event, here's an example:
int main()
    // This is a test
    return 0;
Note also that // is in addition to, not instead of /* */ comments, so both can be used:
 * This is old style comments
 * Might explain an algorithm here
void foo()
    bar(); // Non-obvious remark here perhaps
Nesting the two different styles of comments is generally ok:
// This has new // C++ style comment
// This has an /* old style comment */ in it
/* This has a // C++ style comment */
since the contents of the comment don't confuse either comment. As usual, this is no good though:
/* An old style comment containing an /* old style comment */ */
Take note also that the end of line in the new comments must account for line splicing:
// This is a comment \
and this is part of the same comment as one "long line"!
This means that you should not convert code like this:
#define macro(arg1, arg2) \
    SomeFunction(arg1, /* Some remark */ \
            arg2 /* Some other remark */ \
into this:
#define macro(arg1, arg2) \
    SomeFunction(arg1, // Some remark \
            arg2 // Some other remark \
because the 4 physical lines then become one longer logical line, as if:
#define macro(arg1, arg2) SomeFunction(arg1, // Some remark arg2 // Some other remark )
and hence then a post-preprocessor stage of compilation only sees this:
#define macro(arg1, arg2) SomeFunction(arg1,
Back to Top  Back to Comeau Home

What are universal characters?
What are ucn's?

So-called universal character names, aka UCNs, (e.g., \u0401) are now available in C99 for identifiers, character literals, and string literals (they have always been accepted in comments because they have no special meaning there).
Back to Top  Back to Comeau Home

What is va_copy?

C99 now has a va_copy() macro, for copying va_lists.
Back to Top  Back to Comeau Home

What are hex floating point constants?

C99 now supports Hex floating point constants.
Back to Top  Back to Comeau Home

Back to Top  Back to Comeau Home

What is _Pragma?

_Pragma (note the underscore and the uppercase P here) is a preprocessing operator. This operator provides an alternative to C90's #pragma. In specific, it effectively allows for pragmas as the result of macro substitution. It's form is as a function-like macro:
_Pragma(L"Some literal with \" and \\")
In processing, the beginning and ending double quote is removed, as is the backslash in a backslashed double quote or backslash, as is a literal prefix of L. In other words, the above becomes:
#pragma Some literal with " and \
Since the intent is to deal with macro replacement, the above equivalence is desirable because of something such as:
// Notice the stringizing operator upon arg
#define PragmaFE(arg) _Pragma(#arg)
#define PragmaPack(arg) PragmaFE(pack(arg))
The win here is that this alternative form can help diminish the slew of #if defineds (and perhaps header files that might go along with them) that are often necessary to get some special implementation-defined things done with some code (remember, a normal pragma might apply to something inside a function too (and furthermore, can't be applied to say a function-like macro)). This means things can be arranged into a header file, and then just used:
#include "pragmastuff.h"

void foo() { }

Do you have a question to add?

Do not hesitate to email us if you have any other questions or concerns you would like to see covered.
Back to Top  Back to Comeau Home

Comeau Computing.
Copyright © Comeau Computing. All rights reserved.
Revised: July, 2013.