C99 preprocessor features adopted in C++0x

Note: C++0x is a new version of the C++ programming language standard. IBM® continues to develop and implement the features of the new standard. The implementation of the language level is based on IBM's interpretation of the standard. Until IBM's implementation of all the features of the C++0x standard is complete, including the support of a new C++ standard library, the implementation may change from release to release. IBM makes no attempt to maintain compatibility, in source, binary, or listings and other compiler interfaces, with earlier releases of IBM's implementation of the new features of the C++0x standard and therefore they should not be relied on as a stable programming interface.

In the C++0x standard, several C99 preprocessor features are adopted to provide a common preprocessor interface for C and C++ compilers. This eases porting C source files to the C++ compiler and eliminates some subtle semantic differences that exist between the old C and C++ preprocessors, thus avoiding preprocessor compatibility issues or diverging preprocessor behaviors.

The following C99 preprocessor features are adopted in C++0x:
  • Preprocessor arithmetic with extended integer types
  • Mixed string literal concatenation
  • Diagnostic for header files and include names
  • Increased limit for #line directives
  • Diagnostic for object-like macro definitions
  • The _Pragma operator
  • Variadic macros and empty macro arguments

Preprocessor arithmetic with extended integer types

In the C89, C++98, and C++03 preprocessors, integer literals that have int or unsigned int type are widened to long or unsigned long. However, in the C99 and C++0x preprocessors, all signed and unsigned integer types (character types included) are widened to long long or unsigned long long under normal circumstances in ILE C/C++.

If this feature is enabled, and OPTION(*NOLONGLONG) is set, the preprocessor still uses long long or unsigned long long representations for all integral and character literals in preprocessor controlling expressions. The following example illustrates the case that wchar_t, whose underlying type is unsigned short or unsigned int, depending on LOCALETYPE, is widened to unsigned long long.
#if L'\x0' - L'\x1' < 0 
#error non-C++0x preprocessor arithmetic. 
#else
#error C++0x preprocessor arithmetic! L'\x0' and L'\x1' are widened to \
        unsigned long long 
#endif
The following example shows a case where the long long support is enabled, this feature causes different inclusion branches to be chosen between the non-C++0x preprocessor and the C++0x preprocessor.
#if ~0ull == 0u + ~0u 
#error C++0x preprocessor arithmetic! 0u has the same representation as 0ull, \
        hence ~0ull == 0u + ~0u 
#else 
#error non-C++0x preprocessor arithmetic. 0ul does not have the same representation as 0ull,\
        hence ~0ull != 0u + ~0u 
#endif

Mixed string literal concatenation

Regular strings can be concatenated with wide-string literals, for example:
#include <wchar.h>
#include <stdio.h>
int main()
{
    wprintf(L"Guess what? %ls\n", "I can now concate" L"nate regular strings\
    and wide strings!");
    printf("Guess what? %ls\n", L"I can now concate" "nate strings\
    this way too!");
    return 0;
}
This example prints the following output when it is executed:
Guess what? I can now concatenate regular strings and wide strings!
Guess what? I can now concatenate strings this way too!

Diagnostic for header files and include names

When this feature is enabled, if the first character of a header file name in an #include directive is a digit, the compiler issues a warning message. Consider the following example:
//inc.C
#include "0x/mylib.h"
int main()
{
    return 0;
}
When compiling or preprocessing this example with this feature enabled, the compiler issues the following warning message:
"inc.C", line 1.10: CZP0893(10) The header file name "0x/mylib.h" in the #include directive shall not start with a digit.

Increased limit for #line directives

The upper limit of the #line <integer> preprocessor directives has been increased from 32,767 to 2,147,483,647 for the C++0x preprocessor in conformance with the C99 preprocessor.
#line 1000000 //Valid in C++0x, but invalid in C++98 
int main()
{
    return 0;
}

Diagnostic for object-like macro definitions

If there is no white space between object-like macro name and its replacement list in a macro definition, the C++0x compiler issues a warning message. Consider the following example:
//w.C
//With LANGLVL(*EXTENDED0X), '$' is not part of the macro name,
//thus it begins the replacement list
#define A$B c
#define STR2( x ) # x
#define STR( x ) STR2( x )
char x[] = STR( A$B );
When compiling or preprocessing this example with this feature enabled, the compiler issues the following warning message:
"w.C", line 1.10: CZP0891(10) Missing white space between the identifier "A" and the replacement list.

The _Pragma operator

The _Pragma operator is an alternative method of specifying #pragma directives. For example, the following two statements are equivalent:
#pragma comment(copyright, "IBM 2013")
_Pragma("comment(copyright, \"IBM 2013\")")
The string IBM 2013 is inserted into the C++ object file when the following code is compiled:
_Pragma("comment(copyright, \"IBM 2013\")")
int main()
{
  return 0;
}

Variadic macros and empty macro arguments

Variadic macros and empty macro arguments are supported in C99 and C++0x. This feature enables a mechanism that renames the variable argument identifier from __VA_ARGS__ to a user-defined identifier. Consider the following example:
#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);
This example is expanded to the following code after preprocessing:
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));