I'm trying to pass a comma through multiple levels of macros, but the preprocessor doesn't like that...
// This is just simplified, in reality I have some other variadic function which will
// stop upon encountering the -1 and APPEND_COMMA() may add more args (like `a, b,`)
#include <stdio.h>
#define MACRO_EX(val) printf("%d %d", val -1);
#define MACRO(val) MACRO_EX(val)
#define APPEND_COMMA(a) a,
int main() {
MACRO(APPEND_COMMA(1));
return 0;
}
What exactly is causing the compile failure here?
test.c:10:8: error: too many arguments provided to function-like macro invocation
MACRO(APPEND_COMMA(1));
^
test.c:7:26: note: expanded from macro 'APPEND_COMMA'
#define APPEND_COMMA(a) a,
^
test.c:5:29: note: expanded from macro 'MACRO'
#define MACRO(val) MACRO_EX(val)
^
test.c:3:9: note: macro 'MACRO_EX' defined here
#define MACRO_EX(val) printf("%d %d", val 0);
^
test.c:10:2: error: use of undeclared identifier 'MACRO_EX'
MACRO(APPEND_COMMA(1));
^
test.c:5:20: note: expanded from macro 'MACRO'
#define MACRO(val) MACRO_EX(val)
^
2 errors generated.
The comma seems to be expanded in the called macro, so that MACRO_EX(a,) is called, which is not what I want.
I found some workaround for this by using __VA_ARGS__:
#define MACRO_EX(...) printf("%d %d", __VA_ARGS__ -1);
But I'd really prefer to pass the comma cleanly through all the macros up to the variadic function call and use cleanly named macro parameters [like I intended in my original code].
Is there any way to achieve that?
The only way to guarantee a comma will be passed "cleanly" through macro parameters is to wrap it in parentheses:
#define APPEND_COMMA(a) (a,)
Now the result of APPEND_COMMA will always be a single preprocessor argument.
The obvious problem with this is that it produces printf("%d %d", (1,) -1);, which is now valid preprocessor code, but no longer valid C code. This is rectified by inserting an "unpack" step into the definition of MACRO_EX:
#define IDENTITY(...) __VA_ARGS__
#define MACRO_EX(val) printf("%d %d", IDENTITY val -1);
IDENTITY will unpack the contents of val, assuming val is a parenthesised argument list, during MACRO_EX's rescan step.
What about situations where val might not be parenthesised, because it doesn't contain a comma? The answer is to not let them arise. Arguments that might contain a comma should always be wrapped, so they can always be safely unwrapped at the final point of insertion. Macros need to be designed with the knowledge of whether they anticipate single tokens or lists*. This is the preprocessor's equivalent of a static type constraint: macros like MACRO require an argument of type list, not of type atom (and the calling macros similarly need to be written with the correct type signatures in mind); on those occasions when they need a single argument only, pass them a single-element list.
* It is technically possible to design a macro that tests whether its argument is parenthesised and branches on the result, but you're getting into dark magic territory there. Stick to fixed types for clarity.
Related
From what I understand about macros in C, they are predefined constants that will be used throughout the program with their constant value, so we go ahead and define them to avoid further complications and make the code more readable, so people reading it will understand what is supposed to stay constant and what isn't.
I have read here and there (C programming A Modern Approach, K.N King) that we can define these two functions as macro.
Since I'm somewhat new to C, I can't wrap my head around how can these two be defined as macro?
There are two types of macros: simple substitution macros and function-like macros.
Substitution macros replace one instance of a symbol with another. For example:
#define LEN 10
char str[LEN];
After preprocessing, this becomes:
char str[10];
A function-like macro can take parameters that can be plugged in to whatever gets substituted:
#define MAX(a,b) ((a) > (b) ? (a) : (b))
int x = MAX(2,3);
After preprocessing:
int x = ((2) > (3) ? (2) : (3));
In the case of getchar and putchar, they can be defined as follows:
#define getchar() getc(stdin)
#define putchar(c) putc(c, stdout)
There are basically three types of preprocessor macros:
Simple defined without any value. For example
#define THIS_IS_A_MACRO
This kind of macros are used for conditional compilation.
Symbolic constants. For example
#define SOME_SYMBOLIC_CONSTANT 123
These kind of macros are what you're thinking of.
Function-like macros. Foe example
#define SOME_MACRO(a_macro_argument) printf("Macro invoked with argument %d\n", a_macro_argument)
This kind of macro is used very much like functions, but are replaced by the preprocessor in the source code before the compiler parser sees the code, with the macro arguments replaced with their actual values.
Lets take the function-like macro and how it will be expanded by the preprocessor:
SOME_MACRO(123);
The above will be replaced like
printf("Macro invoked with argument %d\n", 123);
Fully depends on implementation. They can be function also.
Standards don't demand anything explicit about the type of implementation. But you can check here it points Any function declared in a header may be additionally implemented.... as pointed by Eugene.Sh
To say it more clearly, there may be a function in the library or it can be a macro also (for getchar). Classically, the macro for getchar() would be #define getchar() getc(stdin), and getc() might also be a macro.
Standard says that The getc function is equivalent to fgetc, except that if it is implemented as a macro, it may evaluate stream more than once, so the argument should never be an expression with side effects.
Now it boilds down to fgetc in which case we know that it is guaranteed to be a function. Thread safety makes it more likely to be a function.
Thus, in C++, never define getchar and putchar as member functions of a class. In case, they are defined as macros in stdio.h file, the compiler would throw all sorts of strange errors.
#include <stdio.h>
class My_IO_Device
{
int putchar (int c); // seemingly innocent
};
I do not know whether <cstdio> guarantees them to be implemented as functions.
Here is what confuses me:
To define a function-like macro, you use the same '#define' directive, but you put a pair of parentheses immediately after the macro name.
I believe this is to make the code stand out for people other than the author of the program. Like other rules of CAPS for macro names. But the following is where I get confused:
A function-like macro is only expanded if its name appears with a pair of parentheses after it. If you write just the name, it is left alone.
I disagreed instantly after reading it. And gcc -E verified that in the following code
#define FUNC display()
void display()
{
printf("Display\n");
}
int main()
{
FUNC;
return 0;
}
The pre-processed output shows the content of the main() function as expected:
int main()
{
display();
return 0;
}
So what am I missing here? The pre-processor is for tokenizing the source, the macro expansion is a token and the above code was processed that way, the pre-processor isn't supposed to check anything or verify anything, it just dumps tokens. In that case what is the gcc manual trying to convey.
I am learning C programming, so I might be misunderstanding it a great deal as it frequently happens, I searched for a proper explanation and finally resorted to asking here. Please help me with this.
When you define:
#define FUNC display()
FUNC is not a function-like macro; it is an object-like macro that expands to a function call.
A function-like macro looks like:
#define FUNC() display()
Now you must write FUNC() to invoke it. Or, more frequently, it will have arguments:
#define MIN(x, y) ((x) > (y) ? (x) : (y))
and that can be invoked with:
int min = MIN(sin(p), cos(q));
with cautions about the number of times the arguments are expanded.
See also getc() as macro and C standard library function definition. It includes the standard's explanation of why it is important that the simple name of a function-like macro without a following open parenthesis is not expanded, which is what the quote from the GCC manual is telling you.
When a function-like macro is defined, the open parenthesis must 'touch' the macro name:
#define function_like(a) …
#define object_like (…)
Because there's a space after object_like, the open parenthesis is part of the replacement text, not the start of an argument list. When the function-like macro is invoked, there may be spaces between the macro name and the argument list:
function_like (x) // Valid invocation of function_like macro.
However, if you wrote:
int (function_like)(double a) { return asin(a) + 2 * atanh(a); }
this is not an invocation of the function-like macro because the token after function_like is not an open parenthesis.
There are two kinds of macros. They differ mostly in what they look like when they are used. Object-like macros resemble data objects when used, function-like macros resemble function calls.
You may define any valid identifier as a macro, even if it is a C keyword. The preprocessor does not know anything about keywords. This can be useful if you wish to hide a keyword such as const from an older compiler that does not understand it. However, the preprocessor operator can never be defined as a macro, and C++'s named operators cannot be macros when you are compiling C++.
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.
I have two macros in my C code the helps me to compose the name of certain variables. As an example, consider the following:
#define MACROA(name) A_##name
#define MACROB(name) B_##name
void *MACROB(MACROA(object));
So, I'm trying to declare a variable called B_A_object. However, this doesn't work and the compiler throws me the message:
object.c:27:21: error: a parameter list without types is only allowed in a function definition
void *MACROB(MACROA(object));
^
object.c:26:26: note: expanded from macro 'MACROB'
#define MACROB(name) B_##name
^
So, it seems the preprocessor is not taking the result of MACROA(object), but it is considering the expression itself so that it tries to make B_MACROA(object). So, what do I have to do to make the preprocessor consider the result of a macro passed to another macro?
The concatenation operator acts weird. It concatenates first and evaluates later:
void *MACROB(MACROA(object)); // The original line
void *B_MACROA(object); // Becomes this, nothing more to expand
You can solve it this way:
#define CONC(a,b) a ## b
#define MACROA(name) CONC(A_, name)
#define MACROB(name) CONC(B_, name)
I was playing with a macro to enable/disable traces when I came out with the following code when the macro is disabled:
int main()
{
("Hello world");
}
This code is valid and I got the desired effect (nothing happens when the macro is disabled) but I couldn't figure out what exactly is happening. Is the compiler seeing the parenthesis as a "nameless" method declaration?
To make it clearer the code is :
#ifdef TRACE
#define trace printf("%s %d -> ",__FILE__, __LINE__);printf
else
#define trace
#endif
int main()
{
trace("Hello world");
}
Thanks in advance.
If the function name is missing, as in your first example, then it is not a "parenthesis operator". It is simply a syntactic element of an expression that alters the association between operators and operands. In this case it simply does nothing. What you have is just an expression
"Hello world";
which evaluates to a value of char * type, and that value is ignored. You can surround that expression in a redundant pair of ()
("Hello world");
which will not change anything.
In exactly the same way you can write
(5 + 3);
in the middle of your code and get an expression that evaluates to value 8, which is immediately discarded.
Usually compilers generate no code for expression statements that have no side effects. In fact, in C language the result of every expression statement is discarded, so the only expression statements that "make sense" are expression statements with side effects. Compilers are normally fairly good at detecting effectless statements and discarding them (sometimes with a warning).
The warning could be annoying, so writing effectless expression statements like
"Hello world";
might not be a good idea. Typically compilers recognize a cast to void as a request not to generate this warning
(void) "Hello world";
So you might consider redefining your macro accordingly.
Of course, using the above trace technique, you have to remember that if you put something that does have a side effect as an argument for your macro
trace("%d\n", i++);
then in "disabled" form it will look as follows
("%d\n", i++);
(two subexpressions, chained by a comma operator into one expression). The side effect of incrementing i persists in this case, it does not get disabled. The whole thing is equivalent to plain
i++;
Also if you use a function call as an argument
trace(get_trace_name());
the "disabled" form will look as
(get_trace_name());
and the compiler might not be smart enough to realize that the call to get_trace_name() should be discarded. So, be careful when using your macro. Avoid arguments with side effects, avoid arguments with function calls, unless, of course, it is your intent to preserve the side effects when disabling the actual tracing.
Whether it works or not may depend on exactly what you pass as the arguments to the macro (see the side-effects issue mentioned by AndreyT). In this case it is benign. However the following is probably safer since it will result in no text being inserted when the macro is processed and TRACE is not defined:
#ifdef TRACE
#define trace printf("%s %d -> ",__FILE__, __LINE__);printf
#else
#define trace( ... )
#endif
assuming your compiler supports variadic macros. If it does the following would be a better definition perhaps:
#ifdef TRACE
#define trace( fmt, ...) printf("%s %d -> " fmt, __FILE__, __LINE__, __VA_ARGS__ ) ;
#else
#define trace( ... )
#endif
Note that the lack of a comma between "%s %d -> " and fmt is deliberate and required. Note also that the fmt argument must be a literal string constant in order for adjacent string literal concatenation to occur - a variable of any kind would generate an error, but it is bad practice to use a variable for a format specifier in any case.
("Hello world");
is an expression returning a constant pointer to a string. This value is not consumed.
Parenthesis have no specific role and you can omit them:
"Hello world";
#ifdef TRACE
#define trace printf("%s %d -> ",__FILE__, __LINE__);printf
#else
#define trace
#endif
int main {
trace("Hello world");
}
The way that macros work in C is that the compiler will (essentially)* do a literal replace of the identifier.
So in your case, there are two options depending on the value of the #IFDEF
trace("Hello world");
can become
printf("%s %d -> ",__FILE__, __LINE__);printf("Hello world");
or
("Hello world");
The first option is a sequence of valid C code which consists of two printf statements. The second option is a sequence of valid C code which consists of a string (char *) inside unnecessary braces.
If your compiler supports C99 (or you're using gcc which had this feature earlier) you can use variadic macros:
#ifdef TRACE
#define trace(...) printf("%s %d -> ",__FILE__, __LINE__);printf(__VA_ARGS__)
#else
#define trace(...)
#endif
This avoids the problems you can get with side-effects in arguments. If you have a strict C89 compiler, you've got to just avoid side-effects...