Conditional statements based on #define's name - c

I just started doing some C (coming from Java). I'm trying to figure out what the language's approach to a conditional based on a define's name is.
e.g. I have a huge header file that I can't(shouldn't) edit with a lot of defines.
#define GPIO_OTYPER_OT_0 ((uint32_t)0x00000001)
#define GPIO_OTYPER_OT_1 ((uint32_t)0x00000002)
#define GPIO_OTYPER_OT_2 ((uint32_t)0x00000004)
#define GPIO_OTYPER_OT_3 ((uint32_t)0x00000008)
#define GPIO_OTYPER_OT_4 ((uint32_t)0x00000010)
#define GPIO_OTYPER_OT_5 ((uint32_t)0x00000020)
And so on;
I want to make a function/declaration (or whatever to the solution is) to act on the _# part of the define.
(pseudocode)
void initialize(int X) {
GPIOA->MODER |= GPIO_MODER_MODER%X_5;
GPIOA->OTYPER &= ~GPIO_OTYPER_OT_%X;
GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR%X;
GPIOA->PUPDR &= ~GPIO_PUPDR_PUPDR5;
GPIOA->ODR |= GPIO_ODR_ODR_%X;
}
Where %X is int X
All I can think of is a switch statement for each X but X has a large range so the source file would be huge.
edit:
https://github.com/espruino/Espruino/blob/master/targetlibs/stm32f4/lib/stm32f411xe.h
is the header file.

Use ST's GPIO abstraction layer, which can be found here. Notably, see GPIO_InitTypeDef which gives you a structure for what you're doing above, and GPIO_Init which will actually do what you want. The initialization structure takes pins as a bit mask, so as #artless noise suggested in a comment, you can just do 1<<X to create your mask. All the MCU-specific behavior and register mapping is hidden away from your code.
If you are trying to implement your own driver layer as an exercise or because you think the ST library is not very good, then I would still take a look at how they implemented GPIO_Init in the C file. They use shifting, but you'll note that when dealing with the registers, it is not always as easy as 1<<X (though, note that for their configuration structure it is always that easy). Some registers have multiple bits for each pin (mode: 2 bits, pull config: 2 bits, alternate function: 4 bits, split across multiple registers).
edit: I'm not suggesting adding more libraries that you don't already have. The library/code base you referenced the header file in already includes ST's peripheral library, so it makes sense (to me) to use it.

There is no way to insert an arbitrary integer into a macro name. However, your integers are going to be small (smaller than 32 for sure, because all your constants are of a 32-bit type). So you can convert a switch-statement into a one-line expression, like so:
x == 0 ? GPIO_OTYPER_OT_0 : \
x == 1 ? GPIO_OTYPER_OT_1 : \
x == 2 ? GPIO_OTYPER_OT_2 : \
...
x == 31 ? GPIO_OTYPER_OT_31 : 0
Here, you can even make a "default" expression that will generate a runtime error - something like (abort(), (uint32_t)0).
To make this more generic, separate the GPIO_OTYPER_OT_ part into a macro argument, and use the "paste operator" ##:
#define MY_MACRO(name, x) \
x == 0 ? name ## 0 : \
x == 1 ? name ## 1 : \
x == 2 ? name ## 2 : \
...
x == 31 ? name ## _31 : \
(abort(), name ## 0)
Usage example:
GPIOA->ODR |= MY_MACRO(GPIO_ODR_ODR_, x);
You have to make a separate macro for those names that have x in the middle:
#define MY_MACRO2(prefix, x, suffix) ( \
(x) == 0 ? prefix ## 0 ## suffix : \
(x) == 1 ? prefix ## 1 ## suffix : \
...
(x) == 31 ? prefix ## 31 ## suffix : \
(abort(), prefix ## 0 ## suffix))
Here I also added the necessary parentheses (around x and around the whole macro), like it is customary with C macros.
P.S. If your large header file doesn't define macros with numbers up to 31, but has a smaller limit, you cannot use the macro that mentions all these names, because you would get a compilation error. In that case, insert the maximum into the name of the macro. Then you can define them in a "recursive" way:
#define MY_MACRO_MAX1(prefix, x) \
x == 0 ? prefix ## 0 ## suffix : prefix ## 1 ## suffix
#define MY_MACRO_MAX2(prefix, x) \
x == 2 ? prefix ## 2 ## suffix : MY_MACRO_MAX1(prefix, x)
#define MY_MACRO_MAX3(prefix, x) \
x == 3 ? prefix ## 3 ## suffix : MY_MACRO_MAX2(prefix, x)
#define MY_MACRO_MAX4(prefix, x) \
x == 4 ? prefix ## 4 ## suffix : MY_MACRO_MAX3(prefix, x)
#define MY_MACRO_MAX5(prefix, x) \
x == 5 ? prefix ## 5 ## suffix : MY_MACRO_MAX4(prefix, x)
...

Related

Check at runtime if macro was defined

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);
}

Macro concatenation inside other macro concatenation in c

I have the following macros:
#define __IR( x ) ICU.IR[ IR ## x ].BIT.IR
#define _IR( x ) __IR( x )
#define IR( x , y ) _IR( _ ## x ## _ ## y )
I use it in this way:
IR(SCI7, RXI7) = 0;
That expands to:
ICU.IR[ IR_SCI7_RXI7 ].BIT.IR = 0
Instead of use SCI7 and RXI7 I'd like to use sci(channel) and rxi(channel). So I've tried to create the following macros:
#define _sci(x) SCI ## x
#define sci(x) _sci(x)
#define _rxi(x) RXI ## x
#define rxi(x) _rxi(x)
#define channel 7
And then:
IR(sci(channel), rxi(channel)) = 0;
But it didn't work. The compiler returns me:
Error[Pe017]: expected a "]"
I've been trying to with other manners also but without success.
What I'm doing wrong?
The whole macro is expanded with the literal sub-epressions and the macros in the result expression are expanded after that.
So you could write:
#define __IR(x ) ICU.IR[ IR ## x ].BIT.IR
#define _IR(x, y) __IR(_ ## x ## _ ## y)
#define IR(x, y) _IR(x, y)
#define _sci(x) SCI ## x
#define sci(x) _sci(x)
#define _rxi(x) RXI ## x
#define rxi(x) _rxi(x)
#define channel 7
IR(sci(channel), rxi(channel)) = 0;
(The only thing I've really changed is the definition of _IR. On anther note, macro identifiers and symbold beginning with underscores are reserved for the compiler, so you might want to rename your secondary macros.)
You're making the mistake of believing a macro function is like a function call whereas it actually involves text substitution on source code.
In rough terms, the preprocessor will expand IR(sci(channel), rxi(channel)) = 0 to _IR( _sci(channel)_rxi(channel)) = 0 and expands that to ICU.IR[IR_sci(channel)_rxi(channel)].BIT.IR = 0. The result of all that is then compiled as C.
That bit between the square brackets is not a valid C expression at all. The compiler gets confused on that, hence the cryptic error message.
That's the explanation for the problem. The solution? You haven't given enough information to help anyone suggest one.

Compare preprocessor macros for equality

I have some crude generated header from some .dbc files.
Since a few of the messages represent elements from an array the structure is equal and so the generated Macros are equal. Since I fill some array of struct in the code I would like to save effort and use the same macro for all objects, but to ensure the definitions have not changed I would like to test at compile time if the macros are equal.
Example:
#define GET_PATTERN_01_PATTERNPOINT02Y(buf) (0 \
| (uint16)(-(uint16)((buf[7] >> 6) & 0x01) << 15) \
| (uint8)(+(uint8)((buf[6] >> 0) & 0xff) << 0) \
| (uint16)(+(uint16)((buf[7] >> 0) & 0x7f) << 8) \
)
#define GET_PATTERN_02_PATTERNPOINT04Y(buf) (0 \
| (uint16)(-(uint16)((buf[7] >> 6) & 0x01) << 15) \
| (uint8)(+(uint8)((buf[6] >> 0) & 0xff) << 0) \
| (uint16)(+(uint16)((buf[7] >> 0) & 0x7f) << 8) \
)
#if GET_PATTERN_01_PATTERNPOINT02Y != GET_PATTERN_02_PATTERNPOINT04Y
# error blah
#endif
Is this Possible?
If there is some solution in C++ that may also help. But the macros are fixed.
This is a horrible hack, but seems to work for your example for GCC and C11 at least:
#include <assert.h>
#include <string.h>
...
#define STRINGIFY(x) STRINGIFY_(x)
#define STRINGIFY_(x) #x
#define ASSERT_SAME(m1, m2) \
static_assert(strcmp(STRINGIFY(m1(xxx)), STRINGIFY(m2(xxx))) == 0, \
#m1"() and "#m2"() differ!")
ASSERT_SAME(GET_PATTERN_01_PATTERNPOINT02Y, GET_PATTERN_02_PATTERNPOINT04Y);
You might need to pass -std=c11 or -std=gnu11, though the latter shouldn't be needed here.
Explanation:
STRINGIFY(x) returns the expansion of x as a string literal. We need to do the stringification in two steps using STRINGIFY_() because # suppresses macro expansion. (With one step we'd get "<x>" instead of "expanded version of <x>".)
GCC has a built-in version of strcmp() (__builtin_strcmp()) which is used here. It just happens to be able to compare constant strings at compile-time. The code breaks if you pass -fno-builtin (unless you explicitly use __builtin_strcmp()).
static_assert is a C11 compile-time assertion.
With the three ingredients above we can stringify the expanded macros (passing some dummy token that's likely to be unique for the argument) and compare the strings at compile-time.
Yes, this is a hack...
In C++11 there are safer ways to compare strings at compile time -- see e.g. this answer.
As a side note, you could do this at run-time too with zero overhead for GCC and Clang. (The version above won't work for Clang as it's pickier about strcmp(...) == 0 not being an integer constant expression as required by static_assert.) A run-time check like
if (strcmp(STRINGIFY(m1(xxx)), STRINGIFY(m2(xxx))) != 0) {
*report error and exit*
}
gets completely optimized out when the macros are equal. Not even the strings are kept in the read-only data segment (just checked). It's a more robust approach if you can live with having to run the program to discover the problem.
It possible to do this a bit better by using variadic macros to do the stringification:
#define STRINGIFY_VARIADIC(...) #__VA_ARGS__
#define EXPAND_AND_STRINGIFY_VARIADIC(...) STRINGIFY_VARIADIC (__VA_ARGS__)
#define STATIC_ASSERT_IDENTICAL_EXPANSIONS(macro_a, macro_b) \
_Static_assert ( \
( \
__builtin_strcmp ( \
EXPAND_AND_STRINGIFY_VARIADIC (macro_a), \
EXPAND_AND_STRINGIFY_VARIADIC (macro_b) ) \
== 0 \
), \
"expansions of " #macro_a " and " #macro_b " differ" )
This has two advantages: it works with macros which expand to tuples
(e.g. #define FOO thing1, thing2), and it works with macros which take
arguments (without a dummy token like xxx in the other solution). Note that
the final expansions are compared, not the full expansion histories.
So given these #defines:
#define FOO foo
#define BAR bar
#define ARG_DOUBLER(arg) arg, arg
#define ARG_ITSELF(arg) arg
#define OTHER_ARG_DOUBLER(arg) ARG_ITSELF (arg), ARG_ITSELF (arg)
#define SECOND_ARG_NUKER(arg1, arg2) arg1
All of these will trigger a compile-time error:
STATIC_ASSERT_IDENTICAL_EXPANSIONS (FOO, BAR);
STATIC_ASSERT_IDENTICAL_EXPANSIONS (ARG_DOUBLER (x), ARG_DOUBLER (y));
STATIC_ASSERT_IDENTICAL_EXPANSIONS (x, ARG_ITSELF (y));
STATIC_ASSERT_IDENTICAL_EXPANSIONS (SECOND_ARG_NUKER (x, y), y);
While of these will compile ok:
STATIC_ASSERT_IDENTICAL_EXPANSIONS (FOO, foo);
STATIC_ASSERT_IDENTICAL_EXPANSIONS (ARG_DOUBLER (x), ARG_DOUBLER (x));
STATIC_ASSERT_IDENTICAL_EXPANSIONS (x, ARG_ITSELF (x));
STATIC_ASSERT_IDENTICAL_EXPANSIONS (SECOND_ARG_NUKER (x, y), x);

How to define a constant conditionally

I want to define some constants in my C file.
Its assembly code like this:
Const1 = 0
Const2 = 0
IF Condition1_SUPPORT
Const1 = Const1 or (1 shl 6)
Const2 = Const2 or (1 shl 3)
ENDIF
IF Condition2_SUPPORT
Const1 = Const1 or (1 shl 5)
Const2 = Const2 or (1 shl 2)
ENDIF
Could you tell me the simplest way to implement this?
And it should be flexible enough because the number of both my constants and conditions is over 10.
After seeing the first three answers, I guess I need to explain more;
What I want to know is how to redefine my constant based on its previous value.
You can do so using preprocessing directives:
#if Condition1_SUPPORT
#define Const1 (1 << 6)
// ...
#elif Condition2_SUPPORT
#define Const1 (1 << 5)
// ...
#endif
To address the edit to the question: you can't redefine a macro based on its previous value. A macro can only have one value at a time and its replacement list is only evaluated when it is invoked, not when it is defined. For example, this is not possible:
#define A 10
#define A A + 10
First, it is an illicit redefinition of the macro: when the second line is handled, A is already defined as a macro, and so it cannot be redefined with a different replacement (you have to #undef the macro name first).
Second, were this licit (and many compilers do accept it), the second line, when invoked, would evaluate to A + 10, not 10 + 10 or 20 as you want: by the time the second macro definition could be invoked, the first definition no longer exists.
You can, however, use different names, like so:
#define INITIAL_A 10
#define A INITIAL_A + 10
You should consider getting one of the introductory books from The Definitive C Book Guide and List; any of them would cover what can be accomplished using the preprocessing directives in some detail.
You can't redefine the value of a constant once you assign it -- if you could, it wouldn't be a constant, would it? Since it looks like you're trying to set various bits in a constant based on preprocessor flags, you could #define separate constants for each condition's contribution, then build the final value at the end:
#if Condition1_SUPPORT
# define Const1_Cond1_Bit (1 << 6)
# define Const2_Cond1_Bit (1 << 3)
#else
# define Const1_Cond1_Bit (0)
# define Const2_Cond1_Bit (0)
#endif
#if Condition2_SUPPORT
# define Const1_Cond2_Bit (1 << 5)
# define Const2_Cond2_Bit (1 << 2)
#else
# define Const1_Cond2_Bit (0)
# define Const2_Cond2_Bit (0)
#endif
#define Const1 (Const1_Cond1_Bit | Const1_Cond2_Bit)
#define Const2 (Const2_Cond1_Bit | Const2_Cond2_Bit)
You can then #undef all the intermediate constants, if namespace pollution is a concern.
You can use pre processor macros to conditionally define a constant variable, like
#if SOME_CONDITION
const int my_constant = 10;
#else
const int my_constant = 5;
#endif
In C, you would use preprocessor macros to accomplish that:
#ifdef COND1_SUPPORT
#define CONST1 CONST1_VAL1
#define CONST2 CONST2_VAL1
#elif COND2_SUPPORT
#define CONST1 CONST1_VAL2
#define CONST2 CONST2_VAL2
#endif

Function-like macro definition in C

I'd like to define a function like MACRO . i.e.
#define foo(x)\
#if x>32\
x\
#else\
(2*x)\
#endif
that is,
if x>32, then foo(x) present x
else, foo(x) present (2*x)
but my GCC complains about:
int a = foo(31);
I think C preprocessor should be handle this correctly. since at compile time, it knows x=33. it could replace foo(33) with (2*33)
You can as follows
#define foo(x) ((x) > 32 ? (x) : (2 * (x)))
But that evaluates x multiple times. You can instead create a static function, which is cleaner
static int foo(int x) {
if(x > 32)
return x;
return 2 * x;
}
Then you are also able to pass things to foo that have side effects, and have the side effect happen only one time.
What you have written is using the #if, #else and #endif preprocessor directives, but you need to use language constructs if you pass variables to the macro and want to evaluate their values. Using if, and else statements as in the actual language constructs don't work either, because control flow statements don't evaluate to values. In other words, an if statement is steering control flow only ("if A, then execute B, else execute C"), not evaluating to any values.
#define \
foo(x) \
({ \
int xx = (x); \
int result = (xx > 32) ? xx : (2*xx); \
result; \
})
int a = foo(31);
Expands out to
int a = if 31>32
31
else
(2*31)
endif;
That's how C macros work, via simple, dumb substitution. If you expect gcc to do anything more complex or intelligent with them, then your expectation is erroneous.
Given that, it's easy to see why your code won't work. An alternative that would suffice for this example would be:
#define foo(x) (x > 32 ? x : 2*x)
On the other hand, I would question whether macros are really the appropriate tool for such a thing to begin with. Just put it in the function and the compiler will inline the code if it thinks it will speed it up.
Consider:
int x = rand()
int y = foo( x );
x is not known at compile time.
The problem is not about the theory: provided that you, for some reason, want to have a macro that expands differently according to the value of a parameter passed to it, and this parameter is a constant, known to the macro preprocessor, there's no reason why it couldn't work... for a generic macro processor... But cpp unluckly does not allow the presence of other macro processor "commands" into a macro definition...
So your
#define foo(x) \
#if x>32 \
x \
#else \
2*x \
#endif
does not expand to
#if X>32
X
#else
2*X
#endif
where X is the known parameter (so change X to e.g. 31), which requires another pass by the preprocessor.
Moreover newlines are ignored, while they are important for such an use; otherwise, the following could be considered as a trick (that need another preprocessing pass however)
#define foo(x,y) \
y if x>32 \
x \
y else \
2*x \
y endif
that with foo(20,#) produces
# if 20>32 20 # else 2*20 # endif
which would work, if it would be
# if 20>32
20
# else
2*20
# endif
... but it is not (and as said, the output of the preprocessor must be feeded to the preprocessor again...)
So my answer is that if you need these things, you can't use the C preprocessor; you should use a uncommon (not standard?) C preprocessor, or just another macro processor, and if you need the sort of things that "cpp" has to "integrate" itself with C, then you can't use a generic one (like M4) so easily...

Resources