Get the value of a macro using a string with macro name - c

I have a set of macro definitions that the name only change on the number between "C_" and "_E". What I need is a macro that gets a integer variable and returns the integer value of the corresponding macro definition in case it exists, if it does not exist, it returns "-1" or gives a compile error. Is that possible? The code I need is something like this:
#include <stdio.h>
#define C_1_E 4
#define C_2_E 2
#define C_3_E 0
#define C_4_E 420
#define STR(x) #x
#define STR_MACRO(x) "C_" STR(x) "_E"
#define MACRO_VAL(x) ... // return the value of the macro C_x_E when x=1,2,3 or 4
void main() {
uint8_t n;
for(n=1;n<=4;n++) printf("val %u: %u\n",n, MACRO_VAL(STR_MACRO(n)));
}
Expected output:
val 1: 4
val 2: 2
val 3: 0
val 4: 420
According to my search, this is not possible, but I can swear I did cross this solution once, but I didn't need it back then although I thought it could be helpful.

If you need to have a macro specifically, not a function, then it must be that a macro that expands to a function call is not acceptable either. That makes sense to me only if you need the conversion of macro number to macro expansion to be performed at compile time, by the preprocessor. That doesn't appear to be a necessity for the example code, but there are cases where it would indeed be needed.
And that's too bad, because the C preprocessor then provides no way to achieve what you ask. Variables do not exist or have values at compile time, so there is no way at compile time for the compiler to convert a variable name to the value it represents, much less to build a macro name out of it, much less to expand such a name to its replacement text.
You could, however, do it with numeric literals instead of a variable:
#define EXPAND(x) x
#define MACRO_VAL(n) EXPAND(C_ ## n ## _E)
printf("val %d: %d\n",n, 1, MACRO_VAL(1));
printf("val %d: %d\n",n, 2, MACRO_VAL(2));
printf("val %d: %d\n",n, 3, MACRO_VAL(3));
printf("val %d: %d\n",n, 4, MACRO_VAL(4));
If you try to expand that with an argument that does not produce the name of a defined macro or in-scope variable then that (almost surely) will produce a compile-time error for a reference to an undefined variable.
If run-time evaluation were acceptable after all, then you could write a function that does it (which you could wrap in a macro if you wanted):
#define MACRO_VAL(n) lookup_macro(n)
#define EXPAND(x) x
#define MACRO_CASE(i) case i: return EXPAND(C_ ## i ## _E)
int lookup_macro(int n) {
switch (n) {
MACRO_CASE(1);
MACRO_CASE(2);
MACRO_CASE(3);
MACRO_CASE(4);
default: return -1;
}
}
That will return -1 for an arithmetic argument that is not covered by the defined cases.
You could also consider a lookup table, possibly wrapped in a function, but that would require somewhat more code to provide a -1 result in the event of an argument that doesn't match any macro, especially if the macro numbers are not all consecutive or if the least of them is not known in advance.

Token pasting approaches are inappropriate as x is a variable name.
Here is a simplistic approach that will work as long as the macro argument is an expression without side effects:
#include <stdio.h>
#define C_1_E 4
#define C_2_E 2
#define C_3_E 0
#define C_4_E 420
// return the value of the macro C_x_E when x=1,2,3 or 4
#define MACRO_VAL(x) ((x) == 1 ? C_1_E : \
(x) == 2 ? C_2_E : \
(x) == 3 ? C_3_E : \
(x) == 4 ? C_4_E : -1)
int main() {
int n;
for (n = 1; n <= 4; n++)
printf("val %u: %u\n", n, MACRO_VAL(n));
return 0;
}

Related

Is there a compiler attribute to decrement enumerator-list values/enumeration-constants (in C)?

When you declare a enum, the constant values of the enumerator-list automatically increment. E.g.
typedef enum{
TEST0 = 0,
TEST_X, // automatically will be 1
TEST_Y, // ...will be 2
...
}test_t;
Is there a way to make the enumeration constants decrease instead of increase the values? For example with a attribute directive before the type definition or any other solution?
So my desired behavioral:
typedef enum{
TEST0 = 0,
TEST_X, // want to be -1
TEST_Y, // want to be -2
...
}test_t;
The only trick/workaround that comes to my mind would be:
typedef enum{
TEST_LOWEST = -2000,
TEST_X, //-1999
TEST_Y, //-1998
...
TEST0 = 0,
}test_t;
I didn't find an attribute, but maybe there's another solution.
But the workaround described above indeed works, too.
There is no way to do it in pure C. I am not aware of any compiler extension allowing it. As a workaround, you could use a line number accessible via __LINE__ macro and subtract it from the start to achieve desired behavior.
#include <stdio.h>
enum {
START = 42 + 1 + __LINE__,
ENUM0 = START - __LINE__,
ENUM1 = START - __LINE__,
ENUM2 = START - __LINE__,
};
int main(void) {
printf("%d %d %d", ENUM0, ENUM1, ENUM2);
}
prints:
42 41 40
The safer alternative could use __COUNTER__ macro available in GCC/CLANG. This macro returns an integer incremented whenever the __COUNTER__ macro is expanded.

Defining C macros in preprocessor if statements

Below I change the value of the function that I call depending on the value of INPUT:
#include <stdio.h>
#define INPUT second
#if INPUT == first
#define FUNCTOCALL(X) first(X)
#elif INPUT == second
#define FUNCTOCALL(X) second(X)
#endif
void first(int x) {
printf("first %d\n", x);
}
void second(int x) {
printf("second %d\n", x);
}
int main() {
FUNCTOCALL(3);
return 0;
}
However, the output is first 3, even if INPUT is equal to second, as above. In fact, the first branch is always entered, regardless of the value of INPUT. I'm completely stumped by this - could someone explain what stupid mistake I'm making?
The c preprocessor only works on integer constant expressions in its conditionals.
If you give it tokens it can't expand (such as first or second where first and second aren't macros)
it'll treat them as 0 and 0 == 0 was true last time I used math. That's why the first branch is always taken.
6.10.1p4:
... After all replacements due to macro expansion and the defined
unary operator have been performed, all remaining identifiers
(including those lexically identical to keywords) are replaced with
the pp-number 0, and then each preprocessing token is converted into a
token. ...
You have no macros first and second defined. Be aware that the pre-processor is not aware of C or C++ function names!* In comparisons and calculations (e. g. #if value or #if 2*X == Y), macros not defined (not defined at all or undefined again) or defined without value evaluate to 0. So, as first and second are not defined, INPUT is defined without value, and the comparison in both #if expressions evaluates to 0 == 0...
However, if you did define the two macros as needed, they would collide with the C function names and the pre-processor would replace these with the macro values as you just defined them, most likely resulting in invalid code (e. g. functions named 1 and 2)...
You might try this instead:
#define INPUT SECOND
#define FIRST 1
#define SECOND 2
#if INPUT == FIRST
#define FUNCTOCALL(X) first(X)
#elif INPUT == SECOND
#define FUNCTOCALL(X) second(X)
#else
# error INPUT not defined
#endif
Note the difference in case, making the macro and the function name differ.
* To be more precise, the pre-processor is not aware of any C or C++ tokens, so it does not know about types like int, double, structs or classes, ... – all it knows is what you make it explicitly aware of with #define, everything else is just text it operates on and, if encountering some known text nodes, replacing them with whatever you defined.

mixture of string and number in macro

I want to use this macro to put (if 'i' is greater than zero) the symbol '^' and the number I pass (i) to the macro
#define ESP(i) ((i>0) ? ("^"(i)) : "")
I want to call it in this way
printf("%+d%s", n1, ESP(i));
where 'i' is the index of a cycle, but the compilation reports me errors;
how can I modify the code to be right?
Somewhat dirty but should work:
#include <stdio.h>
#define DYNFORMAT(n, i) (i>0) ?"%+d%s%d\n" :"%+d%s%s\n", n, (i>0) ?"^" :"", (i>0) ?i :""
int main(void)
{
int i = 0;
printf(DYNFORMAT(42, i));
i = 1;
printf(DYNFORMAT(42, i));
}
This should print:
+42
+42^1
Disclaimer: I am not sure whether this conforms to the Standard and how to get rid of the warning(s) it gives during compilation.
The clean approach would be to use two calls to printf().
This can be implemented as a macro or a function.
As I love the pre-processor, the macro version here:
#define PRINT_ESP(n, i) \
do { \
if (i = 0) \
printf("%+d", n); \
else \
printf("%+d^%d", n, i); \
} while (0);
Macros operate at compile time, not at run time. They can perform a variety of text-mangling tricks, but they do not evaluate anything. (They can certainly, however, expand to code that evaluates something.) Putting the formatted value of variable i into a string involves evaluating i; no macro can do this.
You could instead expand the scope of the macro to include the whole printf() call:
#define PRINT_ESP(n1, i) do { \
printf(((i > 0) ? "%+d^%d" : "%+d"), n1, i); \
} while (0)
Alternatively, you could use a macro to express just the format selection incorporated into the above macro definition, or you could just put the full printf() call above directly into your code.
All of these variations are based on the fact that arguments in excess of those required by the given format are evaluated prior to the call, but ignored by printf() itself.
You don't need the (i) after the "^". Change your macro to this and it should work #define ESP(i) ((i>0) ? ("^") : ("")). Then in your printf statement if you want to print the value of i after the "^" then have something like this printf("%s%d", ESP(i), i); As far as I know I don't think you can format a string to include an integer inside a macro since that would require calling other functions, so you have to bring the i into the string inside your printf.

Extracting the number of digits in a macro constant at compile-time

I need to do some preprocessor magic. Assume that I have a global constant
#define MAX_VALUE 99999
What I need to do is to extract the length of this constant in its decimal representation at compile-time. In other words, I don't want to have another constant
#define MAX_VALUE_STRLEN 5
polluting the global namespace and I don't want to add a place in the code that needs to be changed in the case that MAX_VALUE is modified. If I have a number literal, then I can do something like
#define INTLEN(x) (sizeof(#x)/sizeof((#x)[0]) - 1)
and then INTLEN(99999) would expand to 5 at compile-time. Unfortunately, I can't do something like
INTLEN(MAX_VALUE),
because the preprocessor expands INTLEN first, so that I get
(sizeof("MAX_VALUE")/sizeof(("MAX_VALUE")[0]) - 1)
Is there a preprocessor trick that achieves what I want? Another trickier issue that I should be able to safely ignore is that can this be made generic enough that if someone decides to add a type annotation, say, 99999L to the constant that I can still get the right value?
Stringify using # and two levels of macro expansion, then chop off the terminating NUL:
#define MAX_VALUE 99999
#define STRINGIFY(x) #x
#define LENGTH(x) (sizeof(STRINGIFY(x)) - 1)
#include <stdio.h>
int main()
{
size_t n = LENGTH(MAX_VALUE);
printf("length = %zu\n", n);
return 0;
}

What does #define, EQ(a, b) ((a) == (b)) mean?

I have this been given C code where the heading statement includes the following:
#define, EQ(a, b) ((a) == (b))
What does it mean?
The comma is an error that will prevent the code from compiling: I'll assume that it's a typo.
Given:
#define EQ(a, b) ((a) == (b))
This defines a macro for the equality operator ==.
Using this macro later in the code, you can type, e.g.:
if (EQ(2+2, 4))
instead of:
if (2+2 == 4)
Not very useful, really.
It means nothing: this code is ill-formed. The token immediately following a #define must be an identifier, which , is not.
If the , were to be removed, this would define a function-like macro named EQ that takes two arguments.
Let's take it step by step
#define MAX 10
This will replace every instance of the word "MAX" by 10 in your code file. this is very much like defining a constant variable with one major difference. The interpretation of #define statement is done way before compilation. which helps for an example to use MAX as an array size. Which would have caused a compiler error in many cases if you have used a variable instead.
you can use cpp <filename.c> command in Linux terminal to see what will happen when a macro is executed.
for an example this code:
#define MAX 10
int numbers[MAX];
after preprocessing (i.e. interpretation of the preprocessor macros)
int numbers[10];
note that the #define statement will vanish once interpreted.
This takes us to another example
#define square(x) (x * x)
every instance of square(x) in our code will not only be replaced by (x * x) but also the value of x will be replaced. Which has an effect similar to function deceleration but again it is different
so
square(5) will be replaced by (5 * 5)
Finally our example
#define, EQ(a, b) ((a) == (b))
This will replace every instance of EQ(a, b) by ((a) == (b))
so for an example
EQ(4, 5) will be replaced by ((4) == (5))
Now what does "==" mean? it is the "check if equal" if 4 and 5 are equal the whole expression would evaluate as 1 (which obviously is not true) and thus this expression will end up to be evaluated as 0.
Which more or less like the effect of this function
int EQ(int a, int b)
{
return (a == b);
}
Which could be also written as
int EQ(int a, int b)
{
if (a ==b) return 1;
if (a !=b) return 0;
}
Note that with the macro we avoided two variable declarations and there is no function call really and it is in general quicker. This advantage will be obvious if you have a slower processor (or microprocessor).
Finally let me state the obvious
#define simple_macro 5
int some_integer_variable = 10;
.
.
.
some_integer_variable = simple_macro;
simple_macro = 12; /* illegal statement */
simple_macro++; /* illegal statement */
because after running the preprocessor this will be
int some_integer_variable = 10;
.
.
.
some_integer_variable = 5;
5 = 12;
5 ++;
Oh! I might have talked too much but let me leave you with this (obvious) code
#define MAX 10
int variable = MAX; /*this is a MAX variable */
char some_string[] = "the MAX value"; /* no replacement will happen here */
int variable_MAX; /* no replacement will happen here */
after running the preprocessor will be
int variable = 10;
char some_string[] = "the MAX value";
int variable_MAX;

Resources