I have a log library that uses a macro to trace a message. This macro makes use of predefined macros like __func__ and __PRETTY_FUNCTION__ to indicate in which function/method the message was logged.
The macro of my log library is defined in the main header of my log library, outside any function.
For some reason, the preprocessed code contains __func__ (or __PRETTY_FUNCTION__ if i'm using this one) litterally, just like if these predefined macros didn't exist. But i know they DO exist because if i'm using them without using my lib's trace macro, they work !
Here is my libs macro :
#if _MSC_VER >= 1400 // If >= VS2005
#define _TRACE_FUNC_SIGNATURE __FUNCSIG__
#elif defined(__ANDROID__) || defined( __GNUC__ ) && defined( __cplusplus ) // If G++ and/or Android NDK
#define _TRACE_FUNC_SIGNATURE __func__
#else
#error // Unsupported compiler
#endif
// Forces the reprocessing of x to properly expand __VA_ARGS__ when using MSVC compiler
#define _TRACE_REPROCESS( x ) x
#define _TRACE_X( _methodName_, _logCatPtr_, ... ) \
do { \
::dbg::LogCategory * const _catPtrVal_ = (::dbg::LogCategory *)(_logCatPtr_); \
if( NULL != _catPtrVal_ && _catPtrVal_->IsEnabled() ) \
{ \
_TRACE_REPROCESS( _catPtrVal_->_methodName_( _TRACE_FUNC_SIGNATURE " - " __VA_ARGS__ ); ) \
} \
} while( false )
#define TRACE_E( _logCatPtr_, ... ) _TRACE_X( Error, _logCatPtr_, __VA_ARGS__ )
#define TRACE_W( _logCatPtr_, ... ) _TRACE_X( Warning, _logCatPtr_, __VA_ARGS__ )
#define TRACE_I( _logCatPtr_, ... ) _TRACE_X( Info, _logCatPtr_, __VA_ARGS__ )
I know that these macros have no reason to be defined outside a function, but since i'm only using my trace macro inside functions/methods, then it should be defined there !
I'm using the default Android NDK compiler provided with eclipse, which as I read is some kind of extended G++.
EDIT : If I replace __func__ by an actual string litteral, it works, no syntax error. This lets me think that __func__ is definately not defined when used in my macro.
In some implementations, __func__ is a variable, not a macro (at least in gcc). So, you cannot use it as if it were a string literal.
So, this :
_TRACE_REPROCESS( _catPtrVal_->_methodName_( _TRACE_FUNC_SIGNATURE " - " __VA_ARGS__ ); )
will have to be written differently. I don't know how _catPtrVal_->_methodName_ is implemented, but if it can take multiple parameters, then something like this will probably do the trick :
_TRACE_REPROCESS( _catPtrVal_->_methodName_( _TRACE_FUNC_SIGNATURE, " - " __VA_ARGS__ ); )
If not, then you'll have to use some other way of concatenating __func__ with the rest of the log line (using a std::stringstream eg.).
More details
The C standard specifies __func__ like this :
The identifier __func__ shall be implicitly declared by the translator as if,
immediately following the opening brace of each function definition, the declaration
static const char __func__[] = "function-name";
appeared, where function-name is the name of the lexically-enclosing function.
Ie. it leaves it up to the implementation whether to provide it as a variable, or a macro (as long as it behaves as if it were defined as shown above).
As an example, gcc provides it as a variable, and MSVC provides it as a macro.
I thought I'd add my two cents - it IS possible to use the function signature in preprocessor directives, but you have to capture it first. Here's an example working up to a comparison of __PRETTY_FUNCTION__ and the preprocessor alternative.
#include <stdio.h>
#define CAT(X,Y) X ## Y
#define VAR(X) X
#define VAR_(X) VAR(X)
#define VAL(X) #X
#define VAL_(X) VAL(X)
/* Alias for constexpr cstring */
#define SZ const char*
#define CE_SZ constexpr SZ
/* Alias for assignment with appended log statement */
#define LOG(X, Y) X = Y; CE_SZ VAR_(CAT(INFO_, X)) = \
VAL_(X) " = " VAL_(Y) " (" __FILE__ VAL_(:__LINE__) ")"
/* SZ_A has no preprocessor value */
CE_SZ SZ_A = "Value of SZ_A";
/* SZ_B only has value to the preprocessor during LOG
(no define from inside a define, macro, etc.) */
CE_SZ LOG(SZ_B, "Value of SZ_B");
/* SZ_C has a global preprocessor name and value, but no compile time name */
#define SZ_C "Value of SZ_C"
/* SZ_D associates a compile time name with the value of SZ_C */
CE_SZ LOG(SZ_D, SZ_C);
/*
__PRETTY_FUNCTION__ and __func__ don't expand to string literals, but
to references to strings initialized by the compiler. If you capture the
signature in a preprocessor define, it's available globally; if you pass
it to a preprocessor macro, it's available within the scope of the macro.
__PRETTY_FUNCTION__ depends on compiler implementation (if it's defined
at all) - parameter names will be missing, template typenames and values
will be enumerated, etc.
*/
#define SIG template<typename T = SZ> void test(T caller)
SIG {
/* int main(int, const char**) */
printf(" Called function: %s\n", caller);
/* void test(T) [with T = const char*] */
printf(" Current function: %s\n", __PRETTY_FUNCTION__);
/* template<typename T = const char*> void test(T caller) */
printf(" Preprocessor signature: " VAL_(SIG) "\n");
}
CE_SZ LOG(SZ_E, VAL_(SIG));
int main(int argc, const char *argv[]) {
/* SZ_A = "Value of SZ_A" */
printf("%s = \"%s\"\n", VAL_(SZ_A), SZ_A);
/* SZ_B = "Value of SZ_B" (main.cpp:26) */
printf("%s\n", INFO_SZ_B);
/* SZ_C = "Value of SZ_C" */
printf("%s\n", "SZ_C = " VAL_(SZ_C));
/* SZ_D = "Value of SZ_D" (main.cpp:32) */
printf("%s\n\n", INFO_SZ_D);
test(__PRETTY_FUNCTION__);
/* SZ_E = "template..." (main.cpp:53) */
printf("\n%s\n", INFO_SZ_E);
}
Related
I would like to have macro which will undefine constant passed to it when called.
Something like this:
#define CONSTANT1 123
#define macro(const) \
#ifdef const \
const \
#undef const \
#else \
#error "constant already used once" \
#endif
int main(){
int a = macro(CONSTANT1); // a = 123
int b = macro(CONSTANT1); // <- preprocessor error "constant already used once"
return 0;
}
It is possible to archive this functionality with preprocessor?
I don't think it is possible to get it with standard C preprocessor but it is possible to do it with GCC/CLANG pragmas like push_macro/pop_macro:
// define a macro that will generate error on expansion
#define CONSTANT1 _Pragma("GCC error \"CONSTANT1 expanded more than once\"")
// save this macro and undefine it
#pragma push_macro("CONSTANT1")
#undef CONSTANT1
// let CONSTANT1 expand to 123, but replace with
// previous error-generation macro
#define CONSTANT1 123 _Pragma("pop_macro(\"CONSTANT1\")")
int a = CONSTANT1;
int b = CONSTANT1;
Compiling with gcc/clang produced:
prog.c:8:11: error: CONSTANT1 expanded more than once
8 | int b = CONSTANT1;
Note that pragmas push_macro/pop_macro are quite portable and they are supported by GCC,CLANG,MSVS and Intel C Compiler.
A bit more portable version of failing CONSTANT1 could be:
#define CONSTANT1 sizeof(struct {_Static_assert(0, "CONSTANT1 expanded more than once"); int x; })
It requires C11 compatible compiler.
During the developing of static library I met the necessity to test the library functions.
The functions checks are not the problem. The main problem is to test every macro definition that the library provides.
I've started with the code like
/* For non-vital macro (OS/WORDSIZE detections) */
# if defined(BXI_ARCH_X32)
printf(" defined : BXI_ARCH_X32\n");
# endif
# if defined(BXI_ARCH_X64)
printf(" defined : BXI_ARCH_X64\n");
# endif
<...>
/* For vital macro */
#if defined(BXI_OS)
printf(" defined : BXI_OS : \"%s\"\n", BXI_OS);
#else
print_failed();
#endif
#if defined(BXI_BITS)
printf(" defined : BXI_BITS: %d\n", BXI_BITS);
#else
print_failed();
#endif
#if defined(BXI_ARCH)
printf(" defined : BXI_ARCH: \"%s\"\n", BXI_ARCH);
#else
print_failed();
#endif
That was cool, but very time-consuming. I wanted a tool that will generate the code for me, or some trick that will allow me to autogenerate the tests via macro like this
TEST_MACRO(BXI_OS)
But, as you know, macro definitions can't generate #if/#else/#endif directives.
I needed a solution that will not only check if the macro defined at runtime, but also print its value to output.
I've met a simillar problem and found another nice trick to implement your TEST_BXI_MACRO_EXISTS with no string.h and extra function calls:
#define STRINGIZE_I(x) #x
#define TEST_BXI_MACRO_EXISTS(name) (#name [0] != STRINGIZE_I(name) [0])
This trick uses the same assumption that stringized value of defined macro does not match stringized name of that macro. But for my case I only needed to check if macro is defined as a numeric constant, string literal or empty value. No function-like macros and other stuff.
This is how it works:
#define MACRO "Content"
TEST_BXI_MACRO_EXISTS(MACRO)
// translates to ("MACRO"[0] != "\"Content\""[0])
// first letter of a valid macro name can never be equal to '"'
#define MACRO 3.14
TEST_BXI_MACRO_EXISTS(MACRO)
// translates to ("MACRO"[0] != "3.14"[0])
// first letter of a valid macro name can never be equal to a digit
#define MACRO
TEST_BXI_MACRO_EXISTS(MACRO)
// translates to ("MACRO"[0] != ""[0])
// first letter of a valid macro name can never be equal to a '\0'
This approach can also be easily used to test whether macro defines a numeric constant, string literal or empty value like your approach does by checking the value of STRINGIZE_I(name) [0].
So far I have no idea how to test function-like macros this way, but I thought sharing this with others could be useful anyway.
But, as this is Q&A-style article, I've found the solution.
The final result looks as follows:
TEST_BXI_MACRO_STRING(BXI_OS);
TEST_BXI_MACRO_STRING(BXI_ARCH);
TEST_BXI_MACRO_I32 (BXI_BITS);
TEST_BXI_MACRO_EXISTS_WEAK(BXI_ARCH_X32); // _WEAK as we don't need to fail
TEST_BXI_MACRO_EXISTS_WEAK(BXI_ARCH_X64);
The result:
Let us see every one of them closely
TEST_BXI_MACRO_STRING
This one is pretty simple:
#define TEST_BXI_MACRO_STRING(name) \
do \
{ \
print_macro_name(#name); \
if (!TEST_BXI_MACRO_DEFINED(#name, name(1))) \
print_macro_undefined_exit(); \
if (strlen(name "") == 0) \
print_macro_undefined_exit(); \
print_macro_value_string(name ""); \
} \
while (0)
We just using the idea that C allows const strings auto-concatenation. So when the macro exists we will receive
#define MACRO "Content"
"Content" "" = "Content"
and when it doesn't
"" = ""
Then we look at the length of the resulting string, and when it's 0 - bingo, macro is not defined. This will NOT work for "" macro, but this special case could be checked with TEST_BXI_MACRO_EXISTS
TEST_BXI_MACRO_I32
#define TEST_BXI_MACRO_I32(name) \
do \
{ \
print_macro_name(#name); \
if (!TEST_BXI_MACRO_DEFINED(#name, name(1))) \
print_macro_undefined_exit(); \
if ((5 * name + 1) == 5) \
print_macro_undefined_exit(); \
print_macro_value_signed(name + 0); \
} \
while (0)
NOTE: you can similarly create ...MACRO_U32 version just by replacing the printer formatter.
Here we use the fact that '+' operator could be unary AND binary.
Let us simulate three cases:
#define MACRO (10)
In this case the complete formula will look as follows:
5 * 10 + 1 => 50 + 1 => 51
#define MACRO (0)
In this case the multiplication fades out:
5 * 0 + 1 => 0 + 1 => 1
In some cases you can use this for additional check if the defined macro is 0 (like for preprocessing options and stuff)
#define MACRO
This case shows some math magic:
5 * + 1 => 5 * (+1) => 5 * 1 => 5
As +1 is interpreted as simple 1 we receive 5.
TEST_BXI_MACRO_EXISTS
#define TEST_BXI_MACRO_DEFINED_I(strstr, fnc) (strcmp(#fnc, strstr "(1)"))
#define TEST_BXI_MACRO_DEFINED(str, fnc) TEST_BXI_MACRO_DEFINED_I(str, fnc)
#define TEST_BXI_MACRO_EXISTS(name) \
do \
{ \
print_macro_name(#name); \
if (!TEST_BXI_MACRO_DEFINED(#name, name(1))) \
print_macro_undefined_exit(); \
else \
print_macro_defined(); \
} \
while (0)
This implementation uses the fact that the string value of macro should not expand same as its name (as #define A A is useles)
Additional functions
For those who want the printing functions, here they are:
void print_macro_name(const char * name)
{
printf(" checking: %-20s: ", name);
}
void print_macro_undefined_exit(void)
{
printf("\033[1;31mUNDEFINED\033[0m\n");
exit(1);
}
void print_macro_defined(void)
{
printf("\033[1;33mDEFINED\033[0m\n");
}
void print_macro_undefined(void)
{
printf("\033[1;32mUNDEFINED\033[0m\n");
}
void print_macro_value_string(const char * value)
{
printf("\"%s\"\n", value);
}
void print_macro_value_signed(i32 value)
{
printf("%d\n", value);
}
void print_macro_value_unsigned(u32 value)
{
printf("%u\n", value);
}
I want to implement cross-platform build of my DLL with mingw32/VC.
At the moment everything is perfect with mingw side. However I have to wrap several things in macro for VC (it is built as /TC), for example:
void __attribute__((fastcall)) do1 ( A*, B , C, D );
bool __attribute__((fastcall)) ( *do2 ) ( E*, F );
The first one is simple, just a macro:
#ifdef __MINGW32__
#define __FASTCALL__ __attribute__((fastcall))
#elif _MSC_VER
#define __FASTCALL__ __fastcall
#else
#error "unsupported compiler"
#endif
The problem comes with the second one. Calling convention with a function pointer should looks like
bool ( __fastcall *do2 ) ( E*, F );
I tried the following macro (I skipped ifdef part):
#define __FASTCALLP__(func) (__attribute__((fastcall))(*##func))
#define __FASTCALLP__(func) (__fastcall *##func)
or if pass function name with asterisk:
#define __FASTCALLP__(func) (__attribute__((fastcall))(##func))
#define __FASTCALLP__(func) (__fastcall ##func)
Both failed with
error: pasting "*" and "function_name" does not give a valid
preprocessing token
May I wrong at my approach at all? Or I have to ifdef the whole code blocks or separate it to different files?
The problem is with the Concatenation-Operator ##. It will produce a new preprocessor token by concatenating the left- and right-hand-side, which does not exists (*do2 is no defined token)
Simply omit it and write like this (omitting #ifdefs):
#define __FASTCALL__(func) (__attribute__((fastcall))(func))
#define __FASTCALL__(func) (__fastcall func)
and use like this:
bool __FASTCALL__(do1)(A*, B , C, D);
bool __FASTCALL__(*do2)(E*, F);
I have the following macro function in vanilla C:
#define GLOG(format_string, ...) { \
const char *file = strrchr(__FILE__, '/'); \
char format[256] = "%s:%s!%d\t"; \
strncat(format, format_string, 248); \
strcat(format, "\n"); \
printf(format, __FUNCTION__, file ? file : __FILE__, __LINE__, ##__VA_ARGS__); \
}
which lets me print a debug message containing the current function, file and line number, e.g.
GLOG("count=%d", count);
might print
do_count:counter.c!123 count=456
How can I modify the function to print all local variables if caller omits format_string? e.g.
GLOG();
might print
do_count:counter.c!123 count=456, message="Hello world", array=[7, 8] structure={ptr=0xACE0FBA5E, coord={x=9, y=0}}
If that's not possible, how can I modify it to print just the current function, file and line number? e.g.
do_count:counter.c!123
As is, this returns an error:
error: expected expression before ‘,’ token
as the strncat line is simply
strncat(format, , 248);
First, inspecting all the local variables at runtime by the process itself seems impossible because C doesn't have any means for reflection.
Second, you would be much better off if you wrote the logging macro like that:
#include <stdio.h>
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define GLOGF(fmt, ...) \
printf("%s:%s " fmt "\n", __func__, __FILE__ "!" TOSTRING(__LINE__), ##__VA_ARGS__)
int main (void) {
/* main:test.c!xx count=5 */
GLOGF("count=%d", 5);
/* main:test.c!xx */
GLOGF();
return 0;
}
It is simpler and doesn't incur any additional runtime overhead since the string is concatenated at compile-time.
Also note that I have used __func__ instead of __FUNCTION__, because the latter is non-standard.
I found this link in this answer. It might help you with the first part of the question.
The second, how to get all local variables, is much harder, if not impossible. The reason is that the code, when compiled, doesn't actually have variables, it just have offsets into a memory area (the stack.) It might be possible that your compiler have internal functions that can be used to inspect the stack, but then you only have possible values not the names of the variables. The only solution I see it to use special pre-processor macros to declare local variables, and then a list of structures to represent them for introspection, which will be a lot of both runtime and memory overhead.
As others here have mentioned, C does not have reflection features, and therefore you are not going to be capable of capturing the local variables in a macro call. That being said, if you want something to conditionally happen with a macro depending on if there are or are not any arguments to the macro invocation (i.e., your "non-null" and "null" arguments), then you can do something like the following:
#include <string.h>
#define NULL_IDENT ""
#define IDENT(ident_name) #ident_name
#define MACRO(ident_name) \
if (strcmp(NULL_IDENT, IDENT(ident_name)) == 0) { \
/* add code for a null argument passed to the macro */ } \
else { \
/* add code for a non-null argument passed to the macro */ }
Based on Blagovest Buyukliev's answer, I've come up with the following solution for part 2:
#define GLOG(fmt, ...) do { const char *fn = strrchr(__FILE__, '/'); \
printf("%s:%s!%d\t"fmt"\n",__func__,fn?++fn:__FILE__,__LINE__,##__VA_ARGS__);\
} while(0)
using the preprocessor's string concatenation to simply concatenate a null string if the parameter is omitted.
Additionally, I added the do {...} while(0) to swallow the trailing semicolon so that the following if...else works:
if (...)
GLOG();
else
/* do something else */
(idea from http://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html ).
I'm tidying up some older code that uses 'magic numbers' all over the place to set hardware registers, and I would like to use constants instead of these numbers to make the code somewhat more expressive (in fact they will map to the names/values used to document the registers).
However, I'm concerned that with the volume of changes I might break the magic numbers. Here is a simplified example (the register set is more complex):
const short mode0 = 0;
const short mode1 = 1;
const short mode2 = 2;
const short state0 = 0;
const short state1 = 4;
const short state2 = 8;
so instead of :
set_register(5);
we have:
set_register(state1|mode1);
What I'm looking for is a build time version of:
ASSERT(5==(state1|mode1));
Update
#Christian, thanks for the quick response, I'm interested on a C / non-boost environment answer too because this is driver/kernel code.
NEW ANSWER :
In my original answer (below), I had to have two different macros to support assertions in a function scope and at the global scope. I wondered if it was possible to come up with a single solution that would work in both scopes.
I was able to find a solution that worked for Visual Studio and Comeau compilers using extern character arrays. But I was able to find a more complex solution that works for GCC. But GCC's solution doesn't work for Visual Studio. :( But adding a '#ifdef __ GNUC __', it's easy to choose the right set of macros for a given compiler.
Solution:
#ifdef __GNUC__
#define STATIC_ASSERT_HELPER(expr, msg) \
(!!sizeof \ (struct { unsigned int STATIC_ASSERTION__##msg: (expr) ? 1 : -1; }))
#define STATIC_ASSERT(expr, msg) \
extern int (*assert_function__(void)) [STATIC_ASSERT_HELPER(expr, msg)]
#else
#define STATIC_ASSERT(expr, msg) \
extern char STATIC_ASSERTION__##msg[1]; \
extern char STATIC_ASSERTION__##msg[(expr)?1:2]
#endif /* #ifdef __GNUC__ */
Here are the error messages reported for STATIC_ASSERT(1==1, test_message); at line 22 of test.c:
GCC:
line 22: error: negative width in bit-field `STATIC_ASSERTION__test_message'
Visual Studio:
test.c(22) : error C2369: 'STATIC_ASSERTION__test_message' : redefinition; different subscripts
test.c(22) : see declaration of 'STATIC_ASSERTION__test_message'
Comeau:
line 22: error: declaration is incompatible with
"char STATIC_ASSERTION__test_message[1]" (declared at line 22)
ORIGINAL ANSWER :
I do something very similar to what Checkers does. But I include a message that'll show up in many compilers:
#define STATIC_ASSERT(expr, msg) \
{ \
char STATIC_ASSERTION__##msg[(expr)?1:-1]; \
(void)STATIC_ASSERTION__##msg[0]; \
}
And for doing something at the global scope (outside a function) use this:
#define GLOBAL_STATIC_ASSERT(expr, msg) \
extern char STATIC_ASSERTION__##msg[1]; \
extern char STATIC_ASSERTION__##msg[(expr)?1:2]
There is an article by
Ralf Holly that examines different options for static asserts in C.
He presents three different approaches:
switch case values must be unique
arrays must not have negative dimensions
division by zero for constant expressions
His conclusion for the best implementation is this:
#define assert_static(e) \
do { \
enum { assert_static__ = 1/(e) }; \
} while (0)
Checkout boost's static assert
You can roll your own static assert if you don't have access to a third-party library static assert function (like boost):
#define STATIC_ASSERT(x) \
do { \
const static char dummy[(x)?1:-1] = {0};\
} while(0)
The downside is, of course, that error message is not going to be very helpful, but at least, it will give you the line number.
#define static_assert(expr) \
int __static_assert(int static_assert_failed[(expr)?1:-1])
It can be used anywhere, any times.
I think it is the easiest solution.
Before usage, test it with your compiler carefully.
Any of the techniques listed here should work and when C++0x becomes available you will be able to use the built-in static_assert keyword.
If you have Boost then using BOOST_STATIC_ASSERT is the way to go. If you're using C or don't want to get Boost
here's my c_assert.h file that defines (and explains the workings of) a few macros to handle static assertions.
It's a bit more convoluted that it should be because in ANSI C code you need 2 different macros - one that can work in the area where you have declarations and one that can work in the area where normal statements go. There is a also a bit of work that goes into making the macro work at global scope or in block scope and a bunch of gunk to ensure that there are no name collisions.
STATIC_ASSERT() can be used in the variable declaration block or global scope.
STATIC_ASSERT_EX() can be among regular statements.
For C++ code (or C99 code that allow declarations mixed with statements) STATIC_ASSERT() will work anywhere.
/*
Define macros to allow compile-time assertions.
If the expression is false, an error something like
test.c(9) : error XXXXX: negative subscript
will be issued (the exact error and its format is dependent
on the compiler).
The techique used for C is to declare an extern (which can be used in
file or block scope) array with a size of 1 if the expr is TRUE and
a size of -1 if the expr is false (which will result in a compiler error).
A counter or line number is appended to the name to help make it unique.
Note that this is not a foolproof technique, but compilers are
supposed to accept multiple identical extern declarations anyway.
This technique doesn't work in all cases for C++ because extern declarations
are not permitted inside classes. To get a CPP_ASSERT(), there is an
implementation of something similar to Boost's BOOST_STATIC_ASSERT(). Boost's
approach uses template specialization; when expr evaluates to 1, a typedef
for the type
::interslice::StaticAssert_test< sizeof( ::interslice::StaticAssert_failed<true>) >
which boils down to
::interslice::StaticAssert_test< 1>
which boils down to
struct StaticAssert_test
is declared. If expr is 0, the compiler will be unable to find a specialization for
::interslice::StaticAssert_failed<false>.
STATIC_ASSERT() or C_ASSERT should work in either C or C++ code (and they do the same thing)
CPP_ASSERT is defined only for C++ code.
Since declarations can only occur at file scope or at the start of a block in
standard C, the C_ASSERT() or STATIC_ASSERT() macros will only work there. For situations
where you want to perform compile-time asserts elsewhere, use C_ASSERT_EX() or
STATIC_ASSERT_X() which wrap an enum declaration inside it's own block.
*/
#ifndef C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546
#define C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546
/* first some utility macros to paste a line number or counter to the end of an identifier
* this will let us have some chance of generating names that are unique
* there may be problems if a static assert ends up on the same line number in different headers
* to avoid that problem in C++ use namespaces
*/
#if !defined( PASTE)
#define PASTE2( x, y) x##y
#define PASTE( x, y) PASTE2( x, y)
#endif /* PASTE */
#if !defined( PASTE_LINE)
#define PASTE_LINE( x) PASTE( x, __LINE__)
#endif /* PASTE_LINE */
#if!defined( PASTE_COUNTER)
#if (_MSC_VER >= 1300) /* __COUNTER__ introduced in VS 7 (VS.NET 2002) */
#define PASTE_COUNTER( x) PASTE( x, __COUNTER__) /* __COUNTER__ is a an _MSC_VER >= 1300 non-Ansi extension */
#else
#define PASTE_COUNTER( x) PASTE( x, __LINE__) /* since there's no __COUNTER__ use __LINE__ as a more or less reasonable substitute */
#endif
#endif /* PASTE_COUNTER */
#if __cplusplus
extern "C++" { // required in case we're included inside an extern "C" block
namespace interslice {
template<bool b> struct StaticAssert_failed;
template<> struct StaticAssert_failed<true> { enum {val = 1 }; };
template<int x> struct StaticAssert_test { };
}
}
#define CPP_ASSERT( expr) typedef ::interslice::StaticAssert_test< sizeof( ::interslice::StaticAssert_failed< (bool) (expr) >) > PASTE_COUNTER( IntersliceStaticAssertType_)
#define STATIC_ASSERT( expr) CPP_ASSERT( expr)
#define STATIC_ASSERT_EX( expr) CPP_ASSERT( expr)
#else
#define C_ASSERT_STORAGE_CLASS extern /* change to typedef might be needed for some compilers? */
#define C_ASSERT_GUID 4964f7ac50fa4661a1377e4c17509495 /* used to make sure our extern name doesn't collide with something else */
#define STATIC_ASSERT( expr) C_ASSERT_STORAGE_CLASS char PASTE( PASTE( c_assert_, C_ASSERT_GUID), [(expr) ? 1 : -1])
#define STATIC_ASSERT_EX(expr) do { enum { c_assert__ = 1/((expr) ? 1 : 0) }; } while (0)
#endif /* __cplusplus */
#if !defined( C_ASSERT) /* C_ASSERT() might be defined by winnt.h */
#define C_ASSERT( expr) STATIC_ASSERT( expr)
#endif /* !defined( C_ASSERT) */
#define C_ASSERT_EX( expr) STATIC_ASSERT_EX( expr)
#ifdef TEST_IMPLEMENTATION
C_ASSERT( 1 < 2);
C_ASSERT( 1 < 2);
int main( )
{
C_ASSERT( 1 < 2);
C_ASSERT( 1 < 2);
int x;
x = 1 + 4;
C_ASSERT_EX( 1 < 2);
C_ASSERT_EX( 1 < 2);
return( 0);
}
#endif /* TEST_IMPLEMENTATION */
#endif /* C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546 */
Try:
#define STATIC_ASSERT(x, error) \
do { \
static const char error[(x)?1:-1];\
} while(0)
Then you can write:
STATIC_ASSERT(a == b, a_not_equal_to_b);
Which may give you a better error message (depending on your compiler).
The common, portable option is
#if 5 != (state1|mode1)
# error "aaugh!"
#endif
but it doesn't work in this case, because they're C constants and not #defines.
You can see the Linux kernel's BUILD_BUG_ON macro for something that handles your case:
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
When condition is true, this becomes ((void)sizeof(char[-1])), which is illegal and should fail at compile time, and otherwise it becomes ((void)sizeof(char[1])), which is just fine.
Ensure you compile with a sufficiently recent compiler (e.g. gcc -std=c11).
Then your statement is simply:
_Static_assert(state1|mode1 == 5, "Unexpected change of bitflags");
#define MODE0 0
#define MODE1 1
#define MODE2 2
#define STATE0 0
#define STATE1 4
#define STATE2 8
set_register(STATE1|STATE1); //set_register(5);
#if (!(5==(STATE1|STATE1))) //MY_ASSERT(5==(state1|mode1)); note the !
#error "error blah blah"
#endif
This is not as elegant as a one line MY_ASSERT(expr) solution. You could use sed, awk, or m4 macro processor before compiling your C code to generate the DEBUG code expansion of MY_ASSERT(expr) to multiple lines or NODEBUG code which removes them for production.