I've come across this expression
((void)(obj), (size_t)0)
What purpose does this expression (that looks like half a function signature) serve here?
It's part of a list of macros I found:
#define ers_alloc(obj,type) ((void)(obj), (type *)aMalloc(sizeof(type)))
#define ers_free(obj,entry) ((void)(obj), aFree(entry))
#define ers_entry_size(obj) ((void)(obj), (size_t)0)
#define ers_destroy(obj) ((void)(obj), (void)0)
#define ers_chunk_size(obj,size) ((void)(obj), (void)(size), (size_t)0)
These macros exist to allow the same code to compile in two configurations. If the controlling macro DISABLE_ERS is not defined, then ers_entry_size(some_o) will expand to this:
((some_o)->entry_size(some_o))
Everywhere ers_entry_size(some_o) is used in code. But the same code has to build successfully even when we define DISABLE_ERS. Those macros could thoretically be defined as
#define ers_alloc(obj,type) ((type *)aMalloc(sizeof(type)))
#define ers_free(obj,entry) (aFree(entry))
#define ers_entry_size(obj) ((size_t)0)
#define ers_destroy(obj) (void)0)
#define ers_chunk_size(obj,size) ((size_t)0)
But what if ers_entry_size(some_o) was the only way that a particular function used some_o? If the macro expands to ((size_t)0), now some_o becomes unused. Modern compilers emit warnings about unsed variables. We can't have our code compile to a bunch of warnings in a valid configuration of the library. That's bad library design.
So instead of the naive "no-op" definition, a smarter one is used. Since the comma operator evaluates each operand and discards all but the last, we can leverage it. When the macro is defined like you noted, ers_entry_size(some_o) will expand to
((void)(some_o), (size_t)0)
The first expression fed to the comma operator evaluates and discards some_o. It's being used now, so there is no warning. The second expression evaluates to the constant, and is the value of the whole parenthesized expression.
Related
I wish to declare a statically allocated array.
Let's take a look at the following code:
#define MAX(a,b) ((a)>(b)?(a):(b))
#define FAST 16
#define SLOW 6
#define MAX_NUM MAX(FAST,SLOW)
U8* pBuffers[MAX_NUM];
When MAX_NUM being evaluated by the GCC compiler(FAST and SLOW are constants)?
I would like to make sure that MAX_NUM is constant and being evaluated as part of a compilation or by the pre-processor.
When you launch the compiler, the following phases are (sequentially) performed:
preprocessing: it manages #define, #ifdef / #endif...
code generation: it produces the machine code runnable on target CPU
optimization: it optimizes depending on user options
During the preprocessing phase, the preprocessor will for example "replace" your line with:
U8* pBuffers[MAX(FAST,SLOW)]
then:
U8* pBuffers[((FAST)>(SLOW)?(FAST):(SLOW))]
then finally:
U8* pBuffers[((16)>(6)?(16):(6))]
Indeed, the preprocessor is not very clever and does not go further.
During the code generation phase, your line will be interpreted as:
U8* pBuffers[16]
Because the code generator is very clever.
The C standard requires the sizes of most arrays to be declared using an integer constant expression, which can be, and in this case is required to be, fully evaluated at compile time. (The only exception is "variable length arrays", and those have to be function-local variables with "automatic storage duration" — not statically allocated.)
Therefore, one answer to your question is you don't have to worry about it. If you write
WHATEVER_TYPE variable[SOME EXPRESSION];
at file scope, either SOME EXPRESSION will be evaluated to a constant at compile time, or compilation will fail and you will get an error.
But a more useful answer is to explain how to see for yourself whether SOME EXPRESSION is an integer constant expression, when you are reading code. First, you have to mentally expand all of the macros. Then, you will presumably have an arithmetic expression of some sort (if not, it's a syntax error).
This arithmetic expression is a constant expression if it has no side-effects, doesn't make any function calls, and doesn't refer to the value of any variable (not even if it is const) (enum constants are fine, though, as are string literals, and sizeof variable as long as variable is completely declared and isn't a variable-length array). It is an integer constant expression if, in addition, it doesn't try to do any floating-point or pointer arithmetic (you are allowed to write a floating-point literal as the immediate operand of a cast, though; for instance ((int)3.1415926) is an integer constant expression).
So, to take your example,
#define MAX(a,b) ((a)>(b)?(a):(b))
#define FAST 16
#define SLOW 6
#define MAX_NUM MAX(FAST,SLOW)
U8* pBuffers[MAX_NUM];
after macro expansion we have
U8* pBuffers[((16)>(6)?(16):(6))];
The expression inside the square brackets has no side effects, doesn't make any function calls, doesn't refer to the value of any variable, and doesn't do any floating-point or pointer arithmetic, so it's an integer constant expression, and the compiler is required to evaluate it at compile time.
By contrast, if you were using this definition of MAX instead:
static inline size_t MAX(size_t a, size_t b)
{ return a > b ? a : b; }
then macro expansion would produce
U8* pBuffers[MAX(16, 8)];
and the expression inside the square brackets would be making a function call, so it wouldn't be an integer constant expression, or even a constant expression, and you would get a compile-time error.
(FYI, the rules in C++ are much more complicated; if you need to know about that, ask a new question.)
MACROS are always evaluated before the compilation process begins. So this code has nothing to worry about and it should work fine.
At the same time, this whole thing is the compiler dependent, I believe with gcc it will work fine. Maybe, for some bare-metal application, it may give a warning.
I have encountered the following debug macro in an embedded device codebase:
extern void DebugPrint(uint8_t *s);
#define DEBUG_MSG(x) do { PRINT_CURRENT_TIME; \
DebugPrint x ; } while(0)
Since there are no parentheses around x in the macro body (at the DebugPrint x part), all calls to this macro (all over the codebase) add another set of parentheses around strings:
DEBUG_MSG(("some debug text"));
Is there any reason to do this? Does it simplify optimizing away these calls in release builds, or something like that? Or is it just plain nonsense?
I thought perhaps there would be additional overloads of DebugPrint with more arguments, but there are none.
Here's a theory:
The preprocessor parses the arguments of a macro expansion in a way that mimics the compiler's expression parsing. In particular it parses terms in parentheses as a single argument.
So the DEBUG_MSG author's intention might have been to enforce the use of parentheses.
This might make sense when the DebugPrint print function would actually be a printf style variadic function. You could call the function with a single string literal or with a variable number of arguments:
DEBUG_MSG(("reached this point in code"));
DEBUG_MSG(("value of x = %i", x));
But this is pure speculation. Can't you just ask the author?
I believe that no. Macros are replaced by the compiler, so they have nothing to do with execution speeds. This:
#define MACRO(x) do_something(x)
MACRO("test");
Is no different than this
#define MACRO(x) do_something x
MACRO(("test"));
Since the compiler will replace them both with the same output:
do_something("test");
which will then compile to produce the same object code.
In the very simple C program below, what is the expected compiler error? gcc is giving me 1 whereas MSVC 2013 is giving me 2.
#define foo
#define bar (defined(foo))
#if bar
#error 1
#else
#error 2
#endif
My questions are hopefully equally simple:
What does the C spec say about the value of defined()? I can't seem
to find anything that talks about setting its value to another
macro.
The actual code is not something I have control over and "#if bar" is used all over the place. What is the simplest way to change the #define so that #if bar will work as "expected" in MSVC? The only thing I can think of is to expand it out:
.
#ifdef foo
#define bar 1
#else
#define bar 2
#endif
The C spec says:
§6.10.1/1 The expression ... may contain unary operator expressions of the form defined identifier or defined(identifier) which evaluate to 1 if the identifier is currently defined as a macro name (that is, if it is predefined or if it has been the subject of a #define preprocessing directive without an intervening #undef directive with the same subject identifier), 0 if it is not.
§6.10.1/4 macro invocations in the list of preprocessing tokens that will become
the controlling constant expression are replaced (except for those macro names modified
by the defined unary operator), just as in normal text. If the token defined is
generated as a result of this replacement process or use of the defined unary operator
does not match one of the two specified forms prior to macro replacement, the behavior is
undefined. 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.
(emphasis mine)
However, how macro replacement is very complex, and I think MSVC is defining foo as defined(bar) which is undefined behavior, wheras GCC is defining foo as 1 correctly. Since MSVC is then in undefined behavior, it does strange things.
As you say, the easiest fix is
#ifdef foo
#define bar 1
#else
#define bar 2
#endif
I believe the compiler will see everything after the name/macro being defined as part of the definition of the name/macro, that is, as program text, not as macro text.
int defined(char s); // prototype of a function named "defined"
#define foo
#define bar defined(foo)
"bar" anywhere in the program text will now be replaced with a call to defined() with no argument (as "foo" is defined as empty).
If a #define is used with no value, like
#define COMMAND_SPI()
does it take value 0 by default?
No, it evaluates to nothing. Literally the symbol gets replaced with nothing.
However, once you have #define FOO, the preprocessor conditional #ifdef FOO will now be true.
Note also that in gcc and possibly other compilers, if you define a macro with -DFOO on the command line, that evaluates to 1 by default.
Since the OP updated his question to reference function-like macros, let's consider a small example.
#define FOO
#define BAR()
FOO
BAR
BAR()
This is not a valid C program, but the preprocessor does not care.
If I compile this with gcc -E Input.c, I get a blank, followed by BAR followed by another blank. This is because the first and third expressions evaluate to nothingness, and the middle expression is not expanded because there are no () after it.
I am developing a PIC MCU program on an ansi-compliant compiler (Microchip XC8).
There are two operation modes, determined via macros during compilation time.
So that I don't want to duplicate one function-like macro due to one line of code, I would like to know if there is any way to write a macro such as
#define FOO //
so that when FOO is substituted it will actually cancel the rest of the line.
Writing a function instead of a macro is out of the question because the delay generated by function calls would disrupt the tight timings of my program (around some microseconds).
You can't make a macro expand to comment out the line, no. // in a macro definition is a comment following the definition, it's not expanded, and IIRC there's a rule saying that you cannot construct a // using token-pasting. Even if you can, expanding it doesn't mean that the macro starts a comment. Basically, you don't get to change the comment syntax using macros.
You could do:
#if DO_NOTHING_MODE
#define FOO(ARG1)
#else
#define FOO(ARG1) ARG1
#endif
and use it like:
#define FUNCTION_LIKE_MACRO(ARG1, ARG2) \
required line; \
FOO(optional line;) \
Although a more common idiom is to design the macro to accept an expression as its argument, rather than a whole line:
#if DO_NOTHING_MODE
#define FOO(ARG1) ((void)0)
#else
#define FOO(ARG1) (ARG1)
#endif
and use it like FOO(optional line);
Either way, if the macro argument has commas in it, then the caller needs to enclose them in parentheses FOO((1,2)), although in C99 you can avoid that by making FOO a variadic macro:
#define FOO(...) (__VA_ARGS__)
You can use the #ifndef directive to achieve the same effect:
#ifndef FOO
your_line_of_code
#endif
EDIT: #SteveJessop made me see I didn't pay attention to this sentence of the OP "I don't want to duplicate one function-like macro due to one line of code". Here is what could be done in that case, if duplicating the function-like macro is not wanted:
// When FOO is defined, BLA in FUNC macro is a no-operation (null statement)
#ifndef FOO
#define BLA() a++
#else
#define BLA()
#endif
#define FUNC() \
BLA(); \
b++;
Comments are removed from the source before macro replacement occurs, so there's no way to define a macro exactly like that. However, it is certainly possible to pass an additional parameter into the macro to specify which code it should generate, or conditionally define the macro depending on the mode for which you are compiling.
#define FOO(...) __VA_ARGS__
And then use FOO(your code here) instead of FOO your code here in the macro.
If your platform doesn't have C99, you can instead use
#define FOO(x) x
and just make sure the argument doesn't contain a , not enclosed in ().