Skip to the content.

C is not a subset of C++

This week I've run into two cases where standard C99 and C++98 don't mix:

Designated Initializers

C99 includes a very handy feature called designated initializers which allow you to define some, but not all, of the elements of an array or structure at compile time.

For example:
int abc[255] = { [42]=1, [43]=2 };
or:
struct xyz {
const char* name;
int age;
};
struct xyz p = { .name="David", .age=42 };
[Downloadable example]

This tends to be kind of handy, especially when trying to bake static structures into your code base (think mappings of enums to strings). The alternative is initialization lists, which require you to know the order of fields in your struct and for you to define values for every field.

C++98 unfortunately doesn't support this feature. I've even seen hints that initialization lists are technically a C++03 feature (yet to find a good reference here).

On a more positive note C++11 now has support for initializer lists for classes (such as std::vector) which could certainly be handy in a number of situations... but alas still no support for designated initializers...

The stdint header

The stdint header is one of my favorite headers. It solves a number of problems when writing portable C code or when you need to serialize data by allowing you to precisely specify the size of basic data types (such as uint8_t). Sadly it's not in C++98 either, so you either need to wait for your compiler to support TR1 or C++11 or use something like boost:cstdint. While GCC has supported this feature for quite some time, it's only in VS2010 that the cstdint header was included.

Hooray.

One other gotcha is that even if your compiler does support the stdint header, you don't get the macros for integer constant expressions by default (so you can define integer literals without having to append a semi-random number of "l" symbols on to the end). Without this you'll see some fun errors when including certain C99 headers, like:

error: 'UINT64_C' was not declared in this scope
So what's the solution?

Turns out you need to define __STDC_CONSTANT_MACROS prior to including <stdint.h> or <cstdint>:

#define __STDC_CONSTANT_MACROS
#include <stdint.h>
Yuck.

I wonder how long it will be until C and C++ diverge into completely incompatible languages.

Edit (2011-11-15):
Torg makes an excellent point that using any C features not supported in C++ is particularly bad for Windows portability. Visual Studio has limited C support outside that required for C++, thus it's not just using C99 features in headers that might be used in C++ code that you need to watch out for, it's being able to compile the code in the first place! If desperate for full C99 support you can take a look at mingw, clang and the Intel C compiler.

Also check out Incompatibilities Between  ISO C and ISO C++ for a more extensive listing of C99/C++98 conflicts.