Comma in C/C++ macro
Because angle brackets can also represent (or occur in) the comparison operators <
, >
, <=
and >=
, macro expansion can't ignore commas inside angle brackets like it does within parentheses. (This is also a problem for square brackets and braces, even though those usually occur as balanced pairs.) You can enclose the macro argument in parentheses:
FOO((std::map<int, int>), map_var);
The problem is then that the parameter remains parenthesized inside the macro expansion, which prevents it being read as a type in most contexts.
A nice trick to workaround this is that in C++, you can extract a typename from a parenthesized type name using a function type:
template<typename T> struct argument_type;
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; };
#define FOO(t,name) argument_type<void(t)>::type name
FOO((std::map<int, int>), map_var);
Because forming function types ignores extra parentheses, you can use this macro with or without parentheses where the type name doesn't include a comma:
FOO((int), int_var);
FOO(int, int_var2);
In C, of course, this isn't necessary because type names can't contain commas outside parentheses. So, for a cross-language macro you can write:
#ifdef __cplusplus__
template<typename T> struct argument_type;
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; };
#define FOO(t,name) argument_type<void(t)>::type name
#else
#define FOO(t,name) t name
#endif
comma (,) in C Macro Definition
Macros are just text replacement, so they can expand to just about anything you want. In this case, the macro is being used to expand into two arguments to a function. The function expects a string and the number of characters in the string as arguments, and the SNS()
macro generates them. So
ft_display_fatal(SNS("File name missing.\n"), 2, 1)
expands into
ft_display_fatal(("File name missing.\n"),(sizeof("File name missing.\n")-1), 2, 1)
This is basically only useful when the parameter is a string literal: sizeof("string")
is the size of the char
array including the trailing null byte, and -1
subtracts that byte to get the number of significant characters in the string. This is the len
argument to the ft_display_fatal
function (I'm not sure why it can't just use strlen()
to get this by itself -- I guess it's a performance optimization).
Using the comma operator when defining a macro
melpomene provided an example. Another example, although you could argue whether it's good or bad, is if you want to use the macro in a loop header.
#define MACRO(X) (X--, X>0)
int x=5;
while(MACRO(x)) {
// Do stuff
}
This example is definitely not the best in the world, but the point is that it would not work if you used semicolons instead to separate the expressions, no matter how you encapsulate them.
trailing comma in define macro
In this case it appears to simply be an array initializer list where the macro expands the list to:
{
foo_auth_detach,
0
};
where the comma is necessary to make the array initializer syntax valid. In this specific case, it didn't make much sense - LIST_ENTRY(foo),
had been much clearer.
But there are other very similar cases where you wish to avoid code repetition by using "X-macros" to centralize all data to one place, and have something like this:
#define LIST \
X(foo) \
X(bar) \
...
static int (*func[])(int x) =
{
#define X(_type) _type##_auth_detach,
LIST
#undef X
0
};
which expands to
{
foo_auth_detach,
bar_auth_detach,
0
};
In this "X macro" case, the ,
is not only necessary to for the final 0
argument, but for every argument provided in the list.
Note that array initializer lists may end with a trailing ,
so 0,
would have been valid. This is also true for enum
lists, since C99. Macro tricks like the ones above is one reason why.
C preprocessor macro doesn't parse comma separated tokens?
It sounds to me like you're carrying over intuitions from the C language itself back to the C preprocessor, and those intuitions are biting you because the CPP doesn't work the same way. Generically in C, functions take typed values as arguments. Expressions are not typed values; they get evaluated to give those things. So what you wind up with when you chain things is a type of inner-out evaluation; and this shapes your intuitions. For example, in evaluating f(g(h(),h()),m())
, f is passed two arguments, but it can't do anything with g(h(),h())
; that has to be evaluated, and the result is a value, and that's the argument passed to f. Say h returns 1, m returns 7, g returns a sum, and f a product. Then g evaluates on the values 1 and 1. f evaluates on the values 2 and 7. Most of C coding uses this language, and you get used to the idea that these inner expressions evaluate, and the resulting values get passed to the functions. But that's not how macros work.
In the weird world of macro invocations (phrased carefully; I'm intentionally ignoring conditional directives), your functions don't take typed values; they take token sequences. The CPP does match parentheses for you, meaning F(())
is an invocation of F
with the argument ()
, as opposed to an invocation with the argument (
followed by a )
token. But in macro land, F(G(H(),H()),M())
invokes F
with two arguments. Argument 1 is the token sequence G(H(),H())
; and argument 2 is the token sequence M()
. We don't evaluate the expression G
to get a typed value, because there aren't typed values; there's only token sequences.
The steps of macro invocation for a function like macro begins with (6.10.3.1) argument substitution (a.s.). During a.s., the CPP looks first at the definition of the macro being called, and notes where the macro's parameters are mentioned in its replacement list. For any such mentions that are not being stringified, and not participating in a paste, the CPP evaluates the corresponding argument, and its evaluated result replaces these qualifying mentions of the parameter in the replacement list. Next, the CPP stringifies (6.10.3.2) and pastes (6.10.3.3) in no particular order. Once all of that is done, the resulting replacement list (6.10.3.4) undergoes rescan and further replacement (r.a.f.r) where it is, as the name suggests, rescanned for further replacements; during this rescanning the particular macro is temporarily disabled ("painted blue", as per 6.10.3.4p2).
So let's walk through this; I'll ignore the fact that you're using a language extension (gcc? clang?) where you're invoking a variadic macro with an insufficient number of arguments (you're not doing that intentionally anyway). We start with:
FX()
That invokes FX
, with a single argument that is an empty token list (note that to the CPP, zero arguments only make sense if you define the macro with zero parameters; F()
is called with an empty argument just as F(,)
is called with two empty ones). So then a.s. happens, which transforms FX
's replacement list from this... to this:
RM_FIRST (FF(__VA_ARGS__) ()) => RM_FIRST (FF() ())
Skipping stringification/pastes since there are none, we then do r.a.f.r. That recognizes RM_FIRST
as a macro. RM_FIRST
has one argument: FF() ()
. So we jump into a recursion level 2... invoking RM_FIRST
.
That invocation of RM_FIRST
itself begins with a.s. Assuming the variadic part is treated as empty, we have the parameter x associated with FF() ()
, but here's where your intuition really fails. x isn't mentioned in the replacement list, so nothing happens to FF() ()
. That's a.s. for you. Treating as per whatever extension applies __VA_ARGS__
as if it's empty, we just get this:
__VA_ARGS__ =>
...IOW, there's nothing there any more. So we're basically done.
I'm guessing you were C-function-intuiting this; in doing so, you were expecting FF() ()
to evaluate, and the result to be passed into RM_FIRST
as an argument, but that's not how macros evaluate.
You can, however, get that to happen with indirection. If you did this instead:
#define RM_FIRST(...) RM_FIRST_I(__VA_ARGS__)
#define RM_FIRST_I(x,...) __VA_ARGS__
...and we go back to when RM_FIRST
is invoked, we have a different story. Here, FF() ()
is part of your variadic list, and __VA_ARGS__
is mentioned. So at that a.s. step, we would get:
RM_FIRST_I(__VA_ARGS__) => RM_FIRST_I( () () ,NULL,NULL ())
(Just being literal... I'm guessing the extra litter is part of your diagnostic; but I'm pretty sure you know where to remove the redundant ()'s). Then, during r.a.f.r., we see RM_FIRST_I
being invoked, and so the story goes.
Comma in C/C++ macro passed to another macro
This solved my problem
__VA_ARGS__ expansion using MSVC
so now I am using
#define EXPAND( x ) x
#define Log_printf( file_name,line, message,...) _snprintf_s(nullptr, 0,0,message, __VA_ARGS__)
#define Log(...) EXPAND (Log_printf(__VA_ARGS__))
C: How to Shield Commas in Macro Arguments?
Use parentheses to shield the comma, and then pass them through a special unparen
macro, defined in the example below:
#include <stdio.h>
#define really_unparen(...) __VA_ARGS__
#define invoke(expr) expr
#define unparen(args) invoke(really_unparen args)
#define fancy_macro(a) printf("%s %s\n", unparen(a))
int main()
{
fancy_macro(("Hello", "World"));
}
The trick here is that the invoke
macro forces an extra expansion, allowing really_unparen
to be called even though it's not followed by parentheses in the source.
Edit: per comment below, this appears to not be necessary in this case. Though I'm sure I've hit a case where I needed it sometime ... and it doesn't hurt.
Macro Expansion: Argument with Commas
MSVC is non-conformant. The standard is actually clear on the point, although it does not feel the need to mention this particular case, which is not exceptional.
When a function-like macro invocation is encountered, the preprocessor:
§6.10.3/11 identifies the arguments, which are possibly empty sequences of tokens separated by non-protected commas , (a comma is protected if it is inside parentheses ()).
§6.10.3.1/1 does a first pass over the macro body, substituting each parameter which is not used in a
#
or##
operation with the corresponding fully macro-expanded argument. (It does no other substitutions in the macro body in this step.)§6.10.3.4/1 rescans the substituted replacement token sequence, performing more macro replacements as necessary.
(The above mostly ignores stringification (#
) and token concatenation (##
), which are not relevant to this question.)
This order of operations unambiguously leads to the behaviour expected by whoever wrote the software.
Apparently (according to @dxiv, and verified here) the following standards-compliant workaround works on some versions of MS Visual Studio:
#define CALL(A,B) A B
#define OUTER(PARAM) CALL(INNER,(PARAM))
#define INNER(A,B,C) whatever
For reference, the actual language from the C11 standard, skipping over the references to #
and ##
handling:
§6.10.3 11 The sequence of preprocessing tokens bounded by the outside-most matching parentheses forms the list of arguments for the function-like macro. The individual arguments within the list are separated by comma preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate arguments.…
§6.10.3.1 1 After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list… is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file…
§6.10.3.4 1 After all parameters in the replacement list have been substituted… [t]he resulting preprocessing token sequence is then rescanned, along with all subsequent preprocessing tokens of the source file, for more macro names to replace.
C-preprocessor: iteratively expand macro to comma-separated list
As the comma is both important to your output and is a syntactic element, you need to make a substitute comma for outputting.
#define COMMA() ,
We will also need some deferring functions so that COMMA
isn't evaluated immediately.
#define EMPTY()
#define DEFER(id) id EMPTY()
Now we can redefine your two macros into
#define CHAIN_COMMA_1(x) DEFER(COMMA)() x CHAIN_COMMA_2
#define CHAIN_COMMA_2(x) DEFER(COMMA)() x CHAIN_COMMA_1
However, your SEE
macro also doesn't like the commas that are placed, and so will error for having too many parameters passed.
You can see that the macro is performing correctly by looking at the output of the preprocessor with the -E
option.
Using comma as macro name in C or C++
Warning, black magic ahead.
Macros can indeed be used, albeit with a preset number of arguments. This number can be arbitrary, but each must be written by hand:
#include <stdio.h>
#include <stdlib.h>
#define MERGE_EXPAND( a , b ) a##b
#define MERGE( a , b ) MERGE_EXPAND( a , b )
#define COUNT_PICK( a , b , c , pick , ... ) pick
#define COUNT( ... ) COUNT_PICK( __VA_ARGS__ , 3 , 2 , 1 , 0 )
#define JOIN_1( a ) a
#define JOIN_2( a , b ) a##b
#define JOIN_3( a , b , c ) a##b##c
#define JOIN( ... ) MERGE( JOIN_ , COUNT( __VA_ARGS__ ) )( __VA_ARGS__ )
int main( void )
{
printf( "%d\n" , JOIN( 12345 ) ) ;
printf( "%d\n" , JOIN( 100,44 ) ) ;
printf( "%d\n" , JOIN( -10,44,9999 ) ) ;
return EXIT_SUCCESS ;
}
The macro COUNT count the number of arguments passed to it. This is done by passing arguments to the helper macro COUNT_PICK, and adding additional argument which are consecutive numbers in reverse order. The number of original arguments passed to COUNT then manipulates the arguments of COUNT_PICK, so that one of the numbers is chosen.
That chosen number is then merged wtih JOIN, resulting in either JOIN_1, JOIN_2, or JOIN_3. The chosen macro is then used with original arguments and simply merges them into a single integer literal.
This example can be expanded by manually defining more JOIN_X macros where X is a consecutive number. Simultaneously the macros COUNT and COUNT_PICK, must be altered as well.
As an additional benefit, passing invalid arguments, like:
JOIN( 10,+44 );
JOIN( 10,-44 );
JOIN( 10,*44 );
JOIN( 10,/44 );
JOIN( /10,44 );
//etc...
will yield a compile time warning, but still allows for arguments that will result in a valid integer constant.
To be used with a Microsoft compiler, tested with SVC14 (Microsoft Visual Studio 2015 Update 3), the code must be amended. Macros COUNT_PICK and MERGE must be wrapped with an additional expand macro:
#define EXPAND(...) __VA_ARGS__
Related Topics
How to Output Coloured Text to a Linux Terminal
Detecting Superfluous #Includes in C/C++
Is Floating-Point Addition and Multiplication Associative
Removing Item from Vector, While in C++11 Range 'For' Loop
How to Succinctly, Portably, and Thoroughly Seed the Mt19937 Prng
How to Pass Parameters Correctly
How to Capture a Unique_Ptr into a Lambda Expression
How to Use Stringstream to Separate Comma Separated Strings
Return Statement VS Exit() in Main()
How to Use Break to Exit Multiple Nested 'For' Loops
Global Memory Management in C++ in Stack or Heap
How to Efficiently Select a Standard Library Container in C++11
Is It a Conforming Compiler Extension to Treat Non-Constexpr Standard Library Functions as Constexpr
What Is the Meaning of the Term "Free Function" in C++
Will Using Goto Leak Variables
Difference Between Angle Bracket ≪ ≫ and Double Quotes " " While Including Header Files in C++