C preprocesor macro chain - c-preprocessor

I have demostrative code below. I would expect the result will be initialized array.
#define _NAME name
#define CFIT(name)\
{ _NAME },
const char * idns[] = {
CFIT("address")
CFIT("device_id")
CFIT("device_bh")
CFIT("device_hw")
CFIT("device_fw")
"" };
...but preprocesor create this:
const char * idns[] = {
{ name },
{ name },
{ name },
{ name },
{ name },
""
};
Surprisingly the C++ preprocesor works as expected. Replace _NAME macro with 'name' token direcly works as well. Any hints? Using 32b mingw 5.3.0.

Let's look at only one invocation; I'll pick this one:
CFIT("address")
The preprocessor first performs argument substitution. At this phase, if the parameter (name) is in the replacement list ({ _NAME },; I'm just stripping whitespace here), and not being stringified or participating in a paste, then the argument is fully expanded and the results are replaced with the parameter. Here, name does not appear in that replacement list, so there's nothing to do. So after argument substitution, you have { _NAME },.
The next step is rescan and further replacement (after stringification and pastes occur, of which there's none). At this stage, the remaining tokens are rescanned so that macros can expand (after blue painting the current macro, but that has no effect here). During this stage, _NAME is recognized as an object-like macro, so its expansion commences. That happens to expand to name, but we're already done with argument substitution so it has no relation to the parameter name at this point... it's just another token.

Related

C macro expansion not working but writing that line explicitly worked

//#define newScope(string, scopeType) ({ \
intrprtr.scope = realloc(intrprtr.scope, intrprtr.scope_layer*sizeof(struct Scope)); \
strncpy(intrprtr.scope[intrprtr.scope_layer-1].string, (string), 255); \
intrprtr.scope[intrprtr.scope_layer-1].scopeType = (scopeType); \
})
//newScope(string, objScope); // <-- wanted to use macro but it doesn't work. I don't get it
intrprtr.scope = realloc(intrprtr.scope, intrprtr.scope_layer*sizeof(struct Scope));
strncpy(intrprtr.scope[intrprtr.scope_layer-1].string, string, 255);
intrprtr.scope[intrprtr.scope_layer-1].scopeType = objScope; // <-- this worked
I wanted the code to be more readable, so I used a macro to wrap us to code. I got the following error if I used the macro.
src/parser.c:114:30: error: no member named 'objScope' in 'struct Scope'
newScope(string, objScope); // <-- wanted to use macro but it doesn't work. I don't get it
~~~~~~~~~~~~~~~~~^~~~~~~~~
src/parser.c:109:48: note: expanded from macro 'newScope'
intrprtr.scope[intrprtr.scope_layer-1].scopeType = (scopeType); \
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
I did not get this error if I write the code explicitly.
Here is the declaration of intrprtr (in parser.h that I included in parser.c)
typedef struct{
FILE* file;
char cur_file_name[255];
int line_num;
struct Scope {
char string[255];
enum ScopeType { msgScope, objScope, codeBlock, func } scopeType;
}*scope;
int scope_layer;
}Intrprtr;
extern Intrprtr intrprtr;
According to my understanding, when I passed objScope to second argument of newScope macro, scopeType should expand to objScope. i.e.
intrprtr.scope[intrprtr.scope_layer-1].scopeType = objScope;
That no member error doesn't make any sense to me especially when intrprtr.scope[intrprtr.scope_layer-1].scopeType = objScope; actually worked. Can someone explain this for me? Thanks
In the replacement tokens intrprtr.scope[intrprtr.scope_layer-1].scopeType = (scopeType);, the scopeType token is replaced by the corresponding macro argument, objScope, both times it appears, but you want the first one to be a literal member name scopeType, not to be replaced.
Change the macro parameter name to something that is not otherwise used in the replacement tokens.

C Macro for defining test methods with callbacks

So you can dynamically define a method with its own name like this:
#define test(name) void name() { print("#name"); }
Then you can call it like:
test(foo);
foo();
I'm wondering though if you can make a "callback"-style form, like this:
#define test(name, body) void name() { print(#name); body(); }
Where it invokes a body that is defined as sort of a "block" like this:
test(dosomething, {
int a = add(1, 1);
assert(a == 2);
})
But more than that, I would like to pass a callback for async functions to say they are complete, like this:
test(dosomething, { (done)
int a = add(1, 1);
assert(a == 2);
done();
})
In addition, I am defining these outside of the main, so it would be defined in the same scope as a normal function. Because of that, the tests aren't going to automatically run. They need to be iterated over. As such, they probably need to be pushed into an array of some sort. So wondering how that could be done, if macros allow you to sort of capture stuff into an array, or to build up an enum one #define at a time.
#define test(name, body) void name() { \
print(#name); \
} \
\
TESTS[CURRENT_TEST++] = &name \ // push the test into a TESTS array.
So then in main you can iterate over them:
int
main() {
iterate over TESTS...
}
To summarize, I am wondering how to #define this at the file body level (i.e. not in main, but at the level of functions):
void afunction() { printf("Foo"); }
test(dosomething, { (done)
int a = add(1, 1);
assert(a == 2);
done();
})
void anotherfunction() { printf("Bar"); }
such that I can iterate over the tests in main.
This suggests blocks are possible in macros.
Looks like you're building some sort of mini test framework using the c preprocessor.
There's a caveat for the bodies; to the C preprocessor, curly brackets and square brackets are just tokens. Parenthesized expressions are recognized (i.e., parentheses are matched), and commas are recognized as delimiters. So for example, this macro invocation:
test(dosomething, { int a = add(1, 1); assert(a == 2); })
...has two arguments despite having two commas (because the second comma is "hugged" in a parenthesized set), but that's a bit misleading. This invocation:
test(dosomething, { enum { red, green, blue }; assert(red+1==green); })
...has four arguments: 1: dosomething, 2: { enum { red, 3: green, and 4: blue }; assert(red+1==green); }. If you're going to do this, you probably want to cover cases like this... there are basic strategies: (a) hug the body in parentheses (you can unwrap it in expansion), or (b) use variadic macros.
They need to be iterated over.
Sounds like a job for x-macros (below I'll be using the parameterized-macro flavor of x-macros).
But more than that, I would like to pass a callback for async functions to say they are complete, like this:
...you can't add an argument in the middle, but the braces don't have to be part of this (they don't help anyway, since the preprocessor ignores them). So for the above, we probably want to pick the hug option. That leaves your invocations looking like this:
test(dosomething, (int a=add(1,1); assert(a==2);), done)
However, since we're ripping the curly braces out, we can put them in arbitrary places in our expansion and do arbitrary things in between. Since I'm guessing you want the same kind of async thing going on, we could just put that thing in the expansion that generates the definition rather as an argument.
Here's roughly what it would look like, using a parameterized macro version of x-macros, and applying an async on expansion (using semaphores to demonstrate how arbitrary this could be):
#define APPLY_TEST_MACROS(macro) \
macro(test_add, (int a=add(1,1); assert(a==2); )) \
macro(test_sub, (int a=sub(5,2); assert(a==3); )) \
macro(test_mul, (int a=mul(3,4); assert(a==12); ))
#define UNWRAP(...) __VA_ARGS__
#define MAKE_ASYNC_SEM(NAME_, BODY_) \
void NAME_() { \
sem_wait(&test_sem_ctl); print(#NAME_); sem_post(&test_sem_ctl); \
UNWRAP BODY_ \
sem_wait(&test_sem_ctl); \
if (0==--tests_remaining) sem_post(&test_sem_done); \
sem_post(&test_sem_ctl); \
}
#define COUNT_TESTS(NAME_, BODY_) +1
sem_t test_sem_ctl;
sem_t test_sem_done;
void init_semaphores() {
sem_init(&test_sem_ctl, 0, 1);
sem_init(&test_sem_done, 0, 0);
}
// iterate over tests to count them
unsigned int tests_remaining = APPLY_TEST_MACROS(COUNT_TESTS);
// define the tests
APPLY_TEST_MACROS(MAKE_ASYNC_SEM)
...and so forth (I'm stopping here because the idea is to convey the idea, not code it for you). The x-macro layout allows you to iterate in the preprocessor, so you can do something like spawn a thread per test; you could also just use this same approach to build an array of test functions if, say, you want to feed your tests to a thread pool.

Static mapping of array index and array content in C

I am having a list of parameters. Each parameter is defined by an unique identifier (ParamID) and some other data (&ParamX, SomeOtherDataX) associated with this parameter. All the available parameters are organized in a table, which is implemented as a struct array (ParameterList[]) in C. Thus, on each row I can see all associated data for one parameter. The following code snippet should (hopefully) make this clearer:
// predefined IDs; not changeable!
#define PARAM_ID_A 10
#define PARAM_ID_B 12
#define PARAM_ID_C 14
// the basic structure of my parameter list
typedef struct ParameterList_t {
int ParamID,
*int ParamAddr,
*float SomeConnectedData
}
// definition of my list in ROM
const ParameterList_t ParameterList[] = {
{ PARAM_ID_A, &Param1, SomeOtherData1},
{ PARAM_ID_B, &Param2, SomeOtherData2},
{ PARAM_ID_C, &Param3, SomeOtherData3}
};
Now I want to create another list, which contains references on a subset of the parameters defined in the ParameterList[] table. This list should also be resided in ROM. I basically want to access all associated data for a subset of the parameters.
const *ParameterList_t ParameterSubListA[] = {
&ParameterList[2], // parameter: PARAM_ID_B
&ParameterList[3], // parameter: PARAM_ID_C
};
The problem here is that the code will be maintained by many people and the parameter list (ParameterList[]) might change frequently and parameters will be sorted into the table at the beginning or in the middle. This means the sub list (ParameterSubListA[]) must be updated to point to the desired parameters if their index (index = row in ParameterList[]) changes.
Question:
Basically my code needs a mapping from ParamID to the index of the ParameterList[] table, preferably by use of the preprocessor and only in ROM. I found different ways to implement this, which are all not satisfying:
Option 1:
Automatically generate a list in the RAM at startup, which maps the ParamID to the index in ParameterList[]. What I get is an array, that could be called CrossRefTable[]:
IndexOfParameterA_InParameterList = CrossRefTable[PARAM_ID_A];
My sublist would then look like this (cannot be constant anymore :/ ):
*ParameterList_t ParameterSubListA[] = {
&ParameterList[CrossRefTable[PARAM_ID_B]], // parameter: PARAM_ID_B
&ParameterList[CrossRefTable[PARAM_ID_C]], // parameter: PARAM_ID_C
};
I am short of RAM, so I would prefer a solution that only uses ROM.
Option 2:
Use a predefined macro __COUNTER__, which increments with each call and generate a macro in each row:
const ParameterList_t ParameterList[] = {
{ PARAM_ID_A, &Param1, SomeOtherData1},
#define PARAM_IDX_A __COUNTER__
{ PARAM_ID_B, &Param2, SomeOtherData2},
#define PARAM_IDX_B __COUNTER__
{ PARAM_ID_C, &Param3, SomeOtherData3}
#define PARAM_IDX_C __COUNTER__
};
My sublist would then look like this:
const *ParameterList_t ParameterSubListA[] = {
&ParameterList[PARAM_IDX_B], // parameter: PARAM_ID_B
&ParameterList[PARAM_IDX_C], // parameter: PARAM_ID_C
};
I would favorise this option, apparently it is not possible to use GCC.
Other Options:
I also figured there might be a possiblity in using X-MACROS, but I am not sure about that.
Boost is also not an option.
Hopefully my explanation is somehow clear...
Since the data is static, I'd say go on and initialize it statically.
Using external tools if the compiler is not capable enough.
parameter_list.c:
const struct ParameterList_t ParameterList[] = {
{ PARAM_ID_A, &Param1, SomeOtherData1},
{ PARAM_ID_C, &Param2, SomeOtherData2},
{ PARAM_ID_B, &Param3, SomeOtherData3}
};
#include "parameter_list_index.h"
const *ParameterList_t ParameterSubListA[] = {
&ParameterList[PARAM_ID_C_INDEX],
&ParameterList[PARAM_ID_B_INDEX],
};
parameter_list.px:
#!/usr/bin/perl -n
print "#define $1_INDEX ".($n++)."\n" if
/^const.*ParameterList\[\]/../^}/ and /^\s*{\s*([^,]+)/;
Makefile:
parameter_list.o: parameter_list.c parameter_list.h
parameter_list_index.h: parameter_list.c
./parameter_list.px $< > $#
This is just a general idea, your implementation may differ of course.
You may choose to generate ParameterList[] the same way or use [PARAM_ID_A_INDEX] = { ... } to make extra sure the indexes match.
Note the code above relies heavily on formatting, which may or may not be ok.
And in any case, some people may find tricks like this inappropriate.
Were I doing this, and I needed flexibility
Then I would have defined an enum that matches the table of data.
(no actual instance of the enum needed, just the definition
Then declared an array that contains some values from the enum.
The values in that array are the offsets into the data array

#define in C with curly braces

I found a new form of "#define" in C but I don't understand what it means. This is source code:
#define OPT_SET_INT(s, l, v, h, i) { OPTION_SET_INT, (s), (l), (v), NULL, \
(h), PARSE_OPT_NOARG, NULL, (i) }
This is the definition of OPTION_SET_INT:
enum parse_opt_type {
/* special types */
OPTION_END,
OPTION_ARGUMENT,
OPTION_GROUP,
OPTION_NUMBER,
/* options with no arguments */
OPTION_BIT,
OPTION_NEGBIT,
OPTION_COUNTUP,
OPTION_SET_INT,
OPTION_SET_PTR,
OPTION_CMDMODE,
/* options with arguments (usually) */
OPTION_STRING,
OPTION_INTEGER,
OPTION_CALLBACK,
OPTION_LOWLEVEL_CALLBACK,
OPTION_FILENAME
};
It is in parse-option.h in this repository:
https://github.com/git/git
Thanks.
There's nothing special about this whatsoever. Everything after the macro name (and parenthesis) gets plopped in-place verbatim, with the exception of the macro parameters, which are replaced.
In this case, the macro is used to populate one entry in an array of struct option.
E.g. In some C file you might have:
struct option options[] = {
OPT_SET_INT(foo, bar, snap, crackle, pop),
OPT_SET_INT(somethingelse, runningout, offake, names, forthis),
};
which becomes:
struct option options[] = {
{ OPTION_SET_INT, foo, bar, snap, NULL, crackle, PARSE_OPT_NOARG, NULL, pop },
{ OPTION_SET_INT, somethingelse, runningout, offake, NULL, names, PARSE_OPT_NOARG, NULL, forthis},
};
(note the \ in the macro definition is escaping the newline, so that the definition can span multiple lines).
See GCC Macro Expansion for more information.

How to make a variable inside a function or macro-function that must be defined only one time?

I call CURRENT_DIR(see below) a lot of times in my program. Like the executable path don't change while the program is running, make no sense define it again each time that I call this function.
So, I'm looking for a solution that once this value has set, it should be not set again.
My current solution is: make a static variable with all values set to 0 and in an if-statement test check if the first character if non-null, if true, then set it. But it's looks like a inelegant.. maybe there is a better solution.. by using some model including macros, I do not know.
See the code:
#define CURRENT_DIR ({ \
static char buffer[MAX_PATH + 1] = { 0 }; \
if(buffer[0] != '\0') \
getcurrentdir(buffer, MAX_PATH); \
buffer; \
})
Instead of the gcc-specific expression statement, I'd use a function (possibly inlined if desired):
const char* currentDir(void)
{
static char buffer[MAX_PATH + 1] = { 0 };
if (buffer[0] == '\0')
{
getcurrentdir(buffer, MAX_PATH);
}
return buffer;
}
This has a few advantages:
It's more portable. (Of course, MAX_PATH and getcurrentdir would be platform-dependent.)
It has better type safety. If the string is meant to be constant, you don't want to allow clients to accidentally modify it.
(The gcc expression statement implementation is broken anyway. The static variable won't be reused across multiple CURRENT_DIR sites in the same scope, and the if test is backwards, so buffer will never be initialized to a non-empty string.)

Resources