Creating C macro with ## and __LINE__ (token concatenation with positioning macro) - c

I want to create a C macro that creates a function with a name based
on the line number.
I thought I could do something like (the real function would have statements within the braces):
#define UNIQUE static void Unique_##__LINE__(void) {}
Which I hoped would expand to something like:
static void Unique_23(void) {}
That doesn't work. With token concatenation, the positioning macros
are treated literally, ending up expanding to:
static void Unique___LINE__(void) {}
Is this possible to do?

The problem is that when you have a macro replacement, the preprocessor will only expand the macros recursively if neither the stringizing operator # nor the token-pasting operator ## are applied to it. So, you have to use some extra layers of indirection, you can use the token-pasting operator with a recursively expanded argument:
#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
#define UNIQUE static void TOKENPASTE2(Unique_, __LINE__)(void) {}
Then, __LINE__ gets expanded to the line number during the expansion of UNIQUE (since it's not involved with either # or ##), and then the token pasting happens during the expansion of TOKENPASTE.
It should also be noted that there is also the __COUNTER__ macro, which expands to a new integer each time it is evaluated, in case you need to have multiple instantiations of the UNIQUE macro on the same line. Note: __COUNTER__ is supported by MS Visual Studio, GCC (since V4.3), and Clang, but is not standard C.

How to auto-generate unique variable names with the line number in them by using macros
This is a generic answer, not addressing the narrow specifics of the OP's question, since there are already adequate answers for that.
I learned this primarily from #Jarod42 here, but also from #Adam.Rosenfield here.
#define CONCAT_(prefix, suffix) prefix##suffix
/// Concatenate `prefix, suffix` into `prefixsuffix`
#define CONCAT(prefix, suffix) CONCAT_(prefix, suffix)
/// Make a unique variable name containing the line number at the end of the
/// name. Ex: `uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0;` would
/// produce `uint64_t counter_7 = 0` if the call is on line 7!
#define MAKE_UNIQUE_VARIABLE_NAME(prefix) CONCAT(prefix##_, __LINE__)
Example program:
macro_make_unique_variable_name_with_line_number.c:
#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h> // For `uint8_t`, `int8_t`, etc.
#include <stdio.h> // For `printf()`
#define CONCAT_(prefix, suffix) prefix##suffix
/// Concatenate `prefix, suffix` into `prefixsuffix`
#define CONCAT(prefix, suffix) CONCAT_(prefix, suffix)
/// Make a unique variable name containing the line number at the end of the
/// name. Ex: `uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0;` would
/// produce `uint64_t counter_7 = 0` if the call is on line 7!
#define MAKE_UNIQUE_VARIABLE_NAME(prefix) CONCAT(prefix##_, __LINE__)
// int main(int argc, char *argv[]) // alternative prototype
int main()
{
printf("Autogenerate unique variable names containing the line number "
"in them.\n\n");
uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_54 = 0;
uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_55 = 0;
uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_56 = 0;
// Uncomment this to suppress the errors.
// (void)counter_54;
// (void)counter_55;
// (void)counter_56;
return 0;
}
SAMPLE OUTPUT:
Notice that the intentionally-produced build errors reveal the autogenerated variable names as counter_56, counter_55, and counter_54, as shown here!:
macro_make_unique_variable_name_with_line_number.c:56:40: error: unused variable ‘counter_56’ [-Werror=unused-variable]
macro_make_unique_variable_name_with_line_number.c:55:40: error: unused variable ‘counter_55’ [-Werror=unused-variable]
macro_make_unique_variable_name_with_line_number.c:54:40: error: unused variable ‘counter_54’ [-Werror=unused-variable]
Full output:
eRCaGuy_hello_world/c$ gcc -Wall -Wextra -Werror -O3 -std=gnu17 macro_make_unique_variable_name_with_line_number.c -o bin/a -lm && bin/a
macro_make_unique_variable_name_with_line_number.c: In function ‘main’:
macro_make_unique_variable_name_with_line_number.c:56:40: error: unused variable ‘counter_56’ [-Werror=unused-variable]
56 | uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_56 = 0;
| ^~~~~~~
macro_make_unique_variable_name_with_line_number.c:39:33: note: in definition of macro ‘CONCAT_’
39 | #define CONCAT_(prefix, suffix) prefix##suffix
| ^~~~~~
macro_make_unique_variable_name_with_line_number.c:45:43: note: in expansion of macro ‘CONCAT’
45 | #define MAKE_UNIQUE_VARIABLE_NAME(prefix) CONCAT(prefix##_, __LINE__)
| ^~~~~~
macro_make_unique_variable_name_with_line_number.c:56:14: note: in expansion of macro ‘MAKE_UNIQUE_VARIABLE_NAME’
56 | uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_56 = 0;
| ^~~~~~~~~~~~~~~~~~~~~~~~~
macro_make_unique_variable_name_with_line_number.c:55:40: error: unused variable ‘counter_55’ [-Werror=unused-variable]
55 | uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_55 = 0;
| ^~~~~~~
macro_make_unique_variable_name_with_line_number.c:39:33: note: in definition of macro ‘CONCAT_’
39 | #define CONCAT_(prefix, suffix) prefix##suffix
| ^~~~~~
macro_make_unique_variable_name_with_line_number.c:45:43: note: in expansion of macro ‘CONCAT’
45 | #define MAKE_UNIQUE_VARIABLE_NAME(prefix) CONCAT(prefix##_, __LINE__)
| ^~~~~~
macro_make_unique_variable_name_with_line_number.c:55:14: note: in expansion of macro ‘MAKE_UNIQUE_VARIABLE_NAME’
55 | uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_55 = 0;
| ^~~~~~~~~~~~~~~~~~~~~~~~~
macro_make_unique_variable_name_with_line_number.c:54:40: error: unused variable ‘counter_54’ [-Werror=unused-variable]
54 | uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_54 = 0;
| ^~~~~~~
macro_make_unique_variable_name_with_line_number.c:39:33: note: in definition of macro ‘CONCAT_’
39 | #define CONCAT_(prefix, suffix) prefix##suffix
| ^~~~~~
macro_make_unique_variable_name_with_line_number.c:45:43: note: in expansion of macro ‘CONCAT’
45 | #define MAKE_UNIQUE_VARIABLE_NAME(prefix) CONCAT(prefix##_, __LINE__)
| ^~~~~~
macro_make_unique_variable_name_with_line_number.c:54:14: note: in expansion of macro ‘MAKE_UNIQUE_VARIABLE_NAME’
54 | uint64_t MAKE_UNIQUE_VARIABLE_NAME(counter) = 0; // `uint64_t counter_54 = 0;
| ^~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors

GCC doesn't require "wrapping" (or realizing) unless the result needs to be "stringified". Gcc has features but ALL can be done with plain C version 1 (and some argue Berkeley 4.3 C is so much faster it's worth learning how to use).
**Clang (llvm) DOES NOT DO WHITE SPACE CORRECTLY for macro expansion - it adds whitespace (which certainly destroy's the result as being a C Identifier for further pre-processing) **, clang simply doesn't do # or * macro expansion as a C Preprocessor is expected to for decades. The prime example is compiling X11, macro "Concat3" is broken, it's result is now MISNAMED C Identifier, which of course fails to build. and i'm beginning to thing build fails are their profession.
I think the answer here is "new C that breaks standards is bad C", these hacks always choose to (clobber namespaces) they change defaults for no reason but do not really "improve C" (excepting to their own say so: which i say is contraption made to explain why they get away with all the breakage no one yet has made them responsible for).
It's not a problem that the earlier C pre-processors did not support UNIq_()__ because they supported #pragma which allows "compiler brand hackery in code to be flagged as hackery" and also function just as well WITHOUT effecting standards: just as changing defaults is useless wonton breakage, and just as changing what a function does while using the same name (namespace clobbering) is ... malware in my opinion

Related

Undefining constant inside macro after single use

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.

C macros, what's the meaning of ((void)0)?

Given the following code written according to the C99 standard:
#define LOW 1
#define MEDIUM 2
#define HIGH 3
#define LOGGING_LEVEL HIGH
#if LOGGING_LEVEL >= MEDIUM
#define LOG_MEDIUM(message) printf(message)
#else
#define LOG_MEDIUM(message) ((void)0)
#endif
void load_configuration() {
//...
LOG_MEDIUM("Configuration loaded\n");
}
what's the purpose of ((void)0) I searched the web a lot but nothing found regarding this.
Plus, why didn't we wrote ; after using printf(message)
The void-cast fixes a compiler warning. Here's an analogous testcase:
int main(void)
{
0; // generates "foo.c:3:2: warning: statement with no effect"
(void)0;
return 0;
}
and (using a script to add gcc's warning flags) you see a warning for the line without a cast:
$ gcc-stricter -c foo.c
foo.c: In function ‘main’:
foo.c:3:2: warning: statement with no effect [-Wunused-value]
0;
^
The extra parentheses and lack of semicolon allow the macro's result to be used interchangeably with the printf.
Main idea is to exclude all LOG_MEDIUM if the criteria was not meet.
After compilation those calls will not affect functionality.

Generate non-stringified text literal macro at build time

Background
In a separate question of mine, I created a function-like-macro that allows me to concatenate a user-supplied text literal to create a macro name, i.e.:
/******************************************************************************
* coconut.h
******************************************************************************/
#define COCONUT_FX_REGISTER (100)
#define COCONUT_BASE_REGISTER (101)
/*******************************************************************************
* pineapple.h
******************************************************************************/
#define PINEAPPLE_FX_REGISTER (200)
#define PINEAPPLE_BASE_REGISTER (201)
/*******************************************************************************
* test.c.
******************************************************************************/
#include <stdio.h>
#include "translation.h"
#include "coconut.h"
#include "pineapple.h"
int main(void) {
int i = getTranslation(FX_REGISTER, COCONUT);
printf("Translation:%d.\n", i);
return 0;
}
/*******************************************************************************
* translation.h
******************************************************************************/
#define getTranslation(x, y) y ## _ ## x
Goal
I would like to extend this logic so that I can use a macro for a default value to pass to getTranslation, i.e.:
#define XFRM(x) #x
#define XFRM2(x) XFRM(x)
#define DEFAULT_PRODUCT XFRM2(COCONUT)
int main(void) {
int i = getTranslation(FX_REGISTER, DEFAULT_PRODUCT);
printf("Translation:%d.\n", i);
return 0;
}
Problem
However, I can't seem to get DEFAULT_PRODUCT to be converted to a non-string text literal.
Build Errors
main.c: In function ‘main’:
main.c:14:35: error: ‘DEFAULT_PRODUCT_FX_REGISTER’ undeclared (first use in this function)
printf("%d\n", getTranslation(FX_REGISTER, DEFAULT_PRODUCT));
^
translation.h:33:25: note: in definition of macro ‘getTranslation’
#define getTranslation(x, y) y ## _ ## x
^
main.c:14:35: note: each undeclared identifier is reported only once for each function it appears in
printf("%d\n", getTranslation(FX_REGISTER, DEFAULT_PRODUCT));
^
translation.h:33:25: note: in definition of macro ‘getTranslation’
#define getTranslation(x, y) y ## _ ## x
Question
How can I create a DEFAULT_PRODUCT macro that resolves to a non-string text literal so that I can create a "default" value to use with getTranslation? This is using GCC set to C99 pedantic.
Sounds like an XY problem.
It seems that macro concatenations are processed simultaneous to macro literal expansions, so I'm afraid there's no way to create a DEFAULT_PRODUCT macro that gets expanded before getTranslation.
My proposal: Create another macro function getDefaultTranslation(x) and you'll easily achieve what you want.
// You may want to add appropriate comments
// so code reviewers know what this is doing.
#define getDefaultTranslation(x) COCONUT ## x
Regarding this question, macro expansion is done layer-by-layer, and at the same layer concatenation has a higher precedence , so adding another layer should work. See ringø's answer below.
You need to add an indirection in order to let the preprocessor expand the macros before doing the concatenation
#define CONCAT(a, b) a ## _ ## b
#define getTranslation(x, y) CONCAT(x,y)
#define XFRM(x) x
#define XFRM2(x) XFRM(x)
#define DEFAULT_PRODUCT XFRM2(COCONUT)
Note that XFRM has its # removed (off x), otherwise the " gives an invalid preprocessing token.
This way you get
int i = FX_REGISTER_COCONUT;

How to define macro function which support no input parameter and support also input parametr in the same time

I want to define a macro function which support at the same time:
1) No input parameter
2) Input parameters
some thing like that:
#define MACRO_TEST(X)\
printf("this is a test\n");\
printf("%d\n",x) // the last printf should not executed if there is no input parameter when calling the macro
In the main:
int main()
{
MACRO_TEST(); // This should display only the first printf in the macro
MACRO_TEST(5); // This should display both printf in the macro
}
You can use sizeof for this purpose.
Consider something like this:
#define MACRO_TEST(X) { \
int args[] = {X}; \
printf("this is a test\n");\
if(sizeof(args) > 0) \
printf("%d\n",*args); \
}
gcc and recent versions of MS compilers support variadic macros - that is macros that work similar to printf.
gcc documentation here:
http://gcc.gnu.org/onlinedocs/gcc/Variadic-Macros.html
Microsoft documentation here:
http://msdn.microsoft.com/en-us/library/ms177415(v=vs.80).aspx
Not exactly that but ...
#include <stdio.h>
#define MTEST_
#define MTEST__(x) printf("%d\n",x)
#define MACRO_TEST(x)\
printf("this is a test\n");\
MTEST_##x
int main(void)
{
MACRO_TEST();
MACRO_TEST(_(5));
return 0;
}
EDIT
And if 0 can be used as skip:
#include <stdio.h>
#define MACRO_TEST(x) \
do { \
printf("this is a test\n"); \
if (x +0) printf("%d\n", x +0); \
} while(0)
int main(void)
{
MACRO_TEST();
MACRO_TEST(5);
return 0;
}
The C99 standard says,
An identifier currently defined as an object-like macro shall not be redefined by another #define reprocessing directive unless the second definition is an object-like macro definition and the two replacement lists are identical. Likewise, an identifier currently defined as a function-like macro shall not be redefined by another #define preprocessing directive unless the second definition is a function-like macro definition that has the same number and spelling of parameters, and the two replacement lists are identical.
I think compiler prompts a warning of redefined MACRO. Hence it is not possible.

Ways to ASSERT expressions at build time in C

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.

Resources