The 2011 revision of the ISO standard for C (dubbed "C11") provides several ease-of-use features, most of which are compatible with C++11. In order to use the normal-looking names I'll show here, you need to include these headers: <stddef.h>, <stdlib.h>, <assert.h>, <complex.h>, <stdnoreturn.h>, <uchar.h>, <stdatomic.h>,
and <stdalign.h>.
Alignment
C11 and C++11 both provide new syntax for specifying alignment. The expression alignof(type-name)
designates the alignment of type-name; it is a constant expression, as is the familiar sizeof(type-name)
. (There's one exception in C: Applying sizeof
to a variable length array, or VLA, produces a non-constant expression.) The expression alignof(char)
is, of course, always 1.
There is a similar syntax for declarations:
int alignas(double) b;
specifies that b
is an int
, but is aligned suitably for a double
. Or for a more realistic example,
alignas(double) unsigned char buf[sizeof(double)];
specifies that buf
is an array of unsigned
char
, whose size and alignment would be suitable to hold a double
.
Alignment can be specified as an integer: alignas(constant-expression)
specifies the constant-expression as an alignment. Thus, alignas(type-name)
means the same thing as alignas(alignof(type-name))
.
For each target platform, there is some type that has the largest alignment requirement; that type can be named by the typedef max_align_t
, so a declaration that specifies alignas(max_align_t)
requests an alignment that will be suitable for any type on that platform. If a program requests an alignment that is greater than alignof(max_align_t)
, the program is not portable because support for an over-aligned type is optional.
The C11 library provides aligned_alloc(size_t bound, size_t nbytes)
, which allocates nbytes
of storage aligned on a bound
boundary. The most common use case heard by the committee was to request a buffer aligned on a cache boundary (typically 32k or 64k); however, you have to check your own compiler's manual because the implementation gets to determine the valid alignments.
Unicode Strings and Constants
The new u8
prefix for strings creates a string (an array of char
) that is encoded using the UTF-8 encoding. If your text editor and your compiler are using the ASCII representation (most are), then the string u8"John Doe"
will contain the same characters as the ordinary string "John Doe"
. The crucial difference comes when your program needs to represent international characters beyond the basic 7-bit ASCII (English) characters. If your text editor and compiler can handle the characters, then your program could contain a string like u8"α Ä Ǽ Ω"
and pass that string to the various C library functions that handle ordinary strings (arrays of char
).
The UTF-8 encoding is increasingly popular; for example, it is the default encoding for XML. To the extent that you have a choice about character representations, it appears to me with the benefit of decades of hindsight, that UTF-8, using the u8
strings, is the simplest and best choice.
However, you may not have this simple choice, so C11 (and C++11) also provide several other Unicode representations. A string like u"αΩ"
creates an array of char16_t
values (encoded in UTF-16); similarly, a string like U"αΩ"
creates an array of char32_t
values (encoded in UTF-32). Also, there are character constants for char16_t
and char32_t
values, written as u'α'
and U'α'
. Unfortunately, if you need to use these more complex features, you may need to know about endian-ness, surrogate characters, differences between Windows and UNIX/Linux representations, and this overview article cannot provide enough details to address all those issues.
Type-Generic Macros
The C99 standard introduced type-generic macros into the standardized library. For example, you could invoke fabs(x)
, where x
is either float
, double
, or long double
. What happened auto-magically was that invocation of the type-generic macro abs
would cause invocation of one of three separate library functions fabsf(float)
, fabs(double)
, or fabsl(long double).
However, in C99, you had no opportunity to use the same magic for your own purposes. Now, in C11, you can create a fabs(x)
that will be portable to any other C11 compiler:
#define fabs(X) _Generic( (X), \ long double: fabsl, \ default: fabs, \ float: fabsf \ ) (X)
This method defines a macro named fabs
, which will cause the invocation of several different library functions, using the new C11 syntax for the _Generic
keyword. That fabs
macro is an ordinary macro defined in the preprocessor. For example, fabs
could be undefined (using #undef
). As you see, type-generic macros provide only a tiny portion of the full-blown overloading that is available in C++, but it's enough for purposes such as the type-generic math library.
Miscellaneous Ease-of-Use Features
It is now possible, in C11 and C++11, to inform the compiler that a function will not return. For example, exit
is a function that does not return, so it can be declared like this:
noreturn void exit(int status);
Using noreturn
in this way can assist the compiler's optimizer, possibly eliminating unnecessary warnings.
C11 and C++11also provide static_assert(constant-expr, string-literal)
; if the constant-expr is zero, then a diagnostic message containing the text of the string-literal will be printed. As the name implies, the static_assert
is evaluated at compile time, so it can prevent compilation with incompatible options; for example
static_assert(sizeof(void*) == 4, "64-bit code generation not supported");
One common use of static_assert
is to verify that resource configuration is adequate:
static_assert(NUMBER_OF_BUCKETS >= 16, "NUMBER_OF_BUCKETS must be at least 16");
The message produced by static_assert
will contain, ind addition to the string-literal argument, the file name, line number, and function name (if any).
The C11 standard provides three macros that are helpful for C/C++ compatibility for programs that use complex floating-point values:
double complex CMPLX(double x, double y); float complex CMPLXF(float x, float y); long double complex CMPLXL(long double x, long double y);
Your C++ version of the program could create corresponding macro definitions (but the C++11 standard does not provide these):
#define CMPLX(x, y) std::complex>double<((double)x, (double)y) #define CMPLXF(x, y) std::complex>float<((float)x, (float)y) #define CMPLXL(x, y) std::complex>long double<((long double)x, (long double)y)
Finally, there's a committee decision that was inadvertently left out of the published standard: The pre-defined macros _ _STDC_VERSION_ _
and _ _STDC_LIB_EXT1_ _
are defined to be 201112L
.
Several other corrections and improvements were made, which won't be itemized here.