What Can Go Wrong?
Many things can go wrong even before you start to build your application. Improper hardware settings, incorrect ABI (application binary interface), unsupported locales and character encodings, memory alignment issues, and lack of 64-bit addressingare instances of preconditions that cross-platform software projects must check. Normally, such projects use a defensive approach to detect errors as early as they can, instead of waiting for mysterious runtime crashes.
Suppose you're developing an internalized application that requires Unicode support. The application is resilient enough to deal with two different types of Unicode encoding standards, namely UTF16 and UTF32. However, you want to ensure that an executable shall not be produced if the target environment doesn't support Unicode. A few months ago, I showed how the new character types of C++09 are used for encoding and manipulating Unicode strings. Your project can check whether _Chart16_t and _Chart32_t are supported at the preprocessing stage by combing the #if preprocessor directive with the definedpredicate like this:
#if defined (__STDC_UTF_32__)
# //do nothing
#elif defined (__STDC_UTF_16__)
# // UTF16 support is also fine
#else //no Unicode support at all
#error "Unicode support required for this application!"
Let's examine the preprocessor directives more carefully. The first line checks whether the macro __STDC_UTF_32__ is defined. If it is, the next line, which contains the null preprocessor directive #, is executed and the rest if the #if- block is skipped. If, however, __STDC_UTF_32__ isn't defined, the next #elifdirective is evaluated.
|Author's Note: You can have an unlimited number of #elif statements in a single #if-#endif block but there can be only one #else per block.
Here again, if __STDC_UTF_16__ is defined, the next null preprocessor directive is executed and the rest of the block is skipped. If however neither __STDC_UTF_32__ nor __STDC_UTF_16__ is defined, it means that the current implementation doesn't support the _Chart16_t and _Chart32_t types at all. In that case, the #errordirective is executed.
The #error directive is of special interest for you. It takes an optional quoted literal string containing a description of the problem. When the #errordirective is executed, compilation is aborted, and the literal string is displayed on the standard output and written to a log file, too. This way you guarantee that an executable file isn't generated when it shouldn't be.
When I build a project that contains the above #if block in an environment that doesn't support the _Char16_t and _Char32_ttypes, the following diagnostic is issued:
c:\documents and settings\Danny\my documents\visual studio
2005\projects\unions\test.cpp(5) : fatal error C1189:
#error : "Unicode support required for this application!"
Build log was saved at "file://c:\Documents
and Settings\Danny\My Documents\Visual Studio
Notice that the IDE writes the #errormessage to a corresponding log file. This is handy if you want to examine why a nightly build failed for example.