Showing posts with label Compile Time Assertions. Show all posts
Showing posts with label Compile Time Assertions. Show all posts

Saturday, December 24, 2011

Using Compile Time Assertions to create better code

In my last entry, ISO releases new standard for the C language, I lamented how the C++11 standard has static_assert() and C11 has _Static_assert(), to give compile time assertions.

Static Assertions are also known as Compile Time Assertions. Their use allows us to put compile time check in our source files, that cause the compilation process to stop if the assertion is not valid. The alternative is to check conditions at run-time incurring performance costs, or having detectable bugs crashing our systems. What if you want to use Static Assertions on compilers that are not up to the latest, just released, standards? You use code that will always fail to compile such as:

int main( void )
{
 int a[ -1 ]; /* Should always fail to compile */
}

From an exchange David Brown and I had on the AVR-GCC list, we came up with the following:

/*
 * Compile Time Assertion:
 *  Usage: STATIC_ASSERT( (msg_count > last_msg), To_Many_Messages_Defined_for_array_size );
 *
 *  STATIC_ASSERT( 1 == 2, One_Not_Equal_To_Two ); that looks like:
 *   assertion_failed_at_line_767_One_Not_Equal_To_Two
 */

#define STATIC_ASSERT_NAME_(line,message)  STATIC_ASSERT_NAME2_(line,message)
#define STATIC_ASSERT_NAME2_(line,message) assertion_failed_at_line_##line##_##message
#define STATIC_ASSERT(claim, message) \
       typedef struct { \
         char STATIC_ASSERT_NAME_(__LINE__,message) [(claim) ? 1 : -1]; \
       } STATIC_ASSERT_NAME_(__LINE__,message)

Admittedly it is a bit of a kludge, however it is still better than letting known issues make it into working code. The native compiler versions should be used when they exist. For example I use the above code myself to detect when an enumerated value list is about to overflow the size of a 8-bit byte:

enum MessagesTag{
 Message0,
 Message1,
 Message2,
 ...
 Messages_Last
};
STATIC_ASSERT( Messages_Last >= 255U, Messages_No_Longer_Fits_In_Byte );

Some unsuspecting person, such as a future Me, could add a number of Messages over the years, and not realize there are now to many for the code to operate correctly.

For more information on compile time assertions check out:


ISO releases new standard for the C language

As a Christmas Present to all, the International Organization for Standardization (ISO) has published the new specifications for the C programming language, ISO/IEC 9899:2011. All for the whopping low price of $300!

Drafts of what has become known as C1X have been available for free up to now. This is the last free draft that I know of: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf.

So far the critiques of the new standard have been unkind, and I'll add my own on the new Static Assertions; also known as Compile Time Assertions. The C1X standard gives Static Assertions, called _Static_assert:

6.7.10 Static assertions

Syntax:

1: static_assert-declaration: _Static_assert ( constant-expression , string-literal ) ;

While the C++0X standard, released as ISO/IEC 14882:2011, calls the same function static_assert (all lower case, no leading underscore):

"In a static_assert-declaration the constant-expression shall be a constant expression (5.19) that can be contextually converted to bool (Clause 4). If the value of the expression when so converted is true, the declaration has no effect. Otherwise, the program is ill-formed, and the resulting diagnostic message (1.4) shall include the text of the string-literal, except that characters not in the basic source character set (2.3) are not required to appear in the diagnostic message.
[ Example: static_assert(sizeof(long) >= 8, "64-bit code generation required for this library."); -end example ]"

Is it really to much to ask for these two groups to actually communicate with each other?