'Spaces between #define arguments
I was confused with the concept that we shouldn't have spaces in #define arguments.
I think the only restriction is that we shouldn't have spaces between the macro name and the immediate ( bracket. Am I correct? Am I not supposed to put spaces even inside the () brackets?
Is the below notation correct
#define AVERAGE_NUMS( min_val, max_val ) ((min_val + max_val) / 2)
Guys, my above #define C++ statement is just an example. I am actually concerned about spaces while using #define. Anyway Thanks for your answers.
Solution 1:[1]
Yes, it's correct. But you should enclose each of the arguments in brackets
#define AVERAGE_NUMS( min_val, max_val ) (((min_val) + (max_val)) / 2)
to avoid operator precedence issues.
Solution 2:[2]
In C, when using macros for small computations like that, you should always put each parameter in the expression in brackets, like:
#define AVERAGE_NUMS(min_val, max_val) (((min_val) + (max_val)) / 2)
The spaces within the macro's argument list are optional, so they don't "hurt". As you already said, a space before the opening bracket changes the meaning of the macro: It will then take no parameter and replaces its occurrence with both what you wanted to be the parameter list as well as the "expression".
If you don't put the arguments in the expression in brackets, you can encounter strange results because the operator precedence might change your expression. This is because macros are just text replacement rules and thus don't respect anything of the programming language (C).
A small example where it fails (This is a strange example, I admit, but there are other functions you'd write as macros where "normal" usages fail):
AVERAGE_NUMS(1 << x, y)
Using your macro definition, this will expand to
((1 << x + y) / 2) // Operator precedence: 1 << (x + y)
But using the macro definition from above, it will expand to
(((1 << x) + (y)) / 2) // Operator precedence: (1 << x) + y
In C++, I strongly advise you not to use macros unless you really have to.
A way better method for calculating the average of two numbers without requiring to specify the type is to use a template method:
template<typename T>
T average_nums(T min_val, T max_val) {
return (min_val + max_val) / T(2);
}
If you are concerned about the performance, you should note that all modern compilers handle this piece of code the same way as it was a macro definition, namely they inline the code. This means that there is no function call involved, but the expression avg(a, b) gets replaced by (a + b) / 2.
The difference between this and macros is that a macro is only a text replacement which happens during precompilation, so the actual compilation step will see something like (a + b) / 2 instead of avg(a, b).
Solution 3:[3]
You are correct, no spaces between macro name and the immediately following open bracket. Spaces anywhere else == fine.
Be careful about the names used for your macro arguments, if you've got a variable called the same name as an argument you'll have strange things happening... For example in your example your argument is max_val, but you've typed Max_val in the macro, so if there was a variable Max_val where you happened to use this macro the code would compile fine, but not compile in other places...
Personally I always have a prefix _ on macro names to help avoid such situations... But purists have told me that underscore is reserved and should not be used, but stuff them :)
Solution 4:[4]
I believe the following excerpts from the C standard from 1999 cover the question of how spaces are treated within macros and they do indeed state that spaces are nothing more than a token separator, with the exception of the case where we differentiate between object-like macros and function-like macros based on whether there's a space between the macro name and the immediately following it opening parenthesis.
5.1.1.2 Translation phases
...
1.3 The source file is decomposed into preprocessing tokens and sequences of white-space characters (including comments). ... Each comment is replaced by one space character. New-line characters are retained. Whether each nonempty sequence of white-space characters other than new-line is retained or replaced by one space character is implementation-defined.
1.4 Preprocessing directives are executed, macro invocations are expanded, and
_Pragma unary operator expressions are executed. ... All preprocessing directives are then deleted.
1.7 White-space characters separating tokens are no longer significant. Each preprocessing token is converted into a token. The resulting tokens are syntactically and semantically analyzed and translated as a translation unit.
...
6.4 Lexical elements
Syntax
token:
- keyword
- identifier
- constant
- string-literal
- punctuator
preprocessing-token:
- header-name
- identifier
- pp-number
- character-constant
- string-literal
- punctuator
- each non-white-space character that cannot be one of the above
Semantics
... Preprocessing tokens can be separated by white space; this consists of comments (described later), or white-space characters (space, horizontal tab, new-line, vertical tab, and form-feed), or both. As described in 6.10, in certain circumstances during translation phase 4, white space (or the absence thereof) serves as more than preprocessing token separation. ...
6.10 Preprocessing directives
Syntax
...
- # define identifier replacement-list new-line
# define identifier lparen identifier-listopt ) replacement-list new-line# define identifier lparen ... ) replacement-list new-line# define identifier lparen identifier-list , ... ) replacement-list new-line
lparen:
a ( character not immediately preceded by white-space
6.10.3 Macro replacement
Constraints
3 There shall be white-space between the identifier and the replacement list in the definition of an object-like macro.
Semantics
10 A preprocessing directive of the form
# define identifier lparen identifier-listopt ) replacement-list new-line# define identifier lparen ... ) replacement-list new-line# define identifier lparen identifier-list , ... ) replacement-list new-line
defines a function-like macro with arguments, similar syntactically to a function call.
Solution 5:[5]
The question is already nine years old, but I think most answers miss the rationale behind the "no spaces before the opening paren" rule (or try to explain why macros are dangerous and templates are better...). The point is that you can use #define to define macros without parameters (i.e. constants) as well as real macros with parameters. Now, if the expansion of a constant starts with an opening parenthesis, the preprocessor must differentiate between the parenthesis belonging to the expansion and the parenthesis starting the macro parameter list. And this is done by (you guessed it) whitespace before the parenthesis.
Example: if you have #define FOUR (2+2) the ( is interpreted as belonging to the expansion and wherever you write FOUR its expanded to (2+2). Note, that the parens are necessary, because otherwise without parens expressions like FOUR*3 would be expanded to 2+2*3 which is 8 - not what you expected. On the other hand, if you define #define DOUBLE(a) ((a)+(a)) the parenthesis starts the parameter list and DOUBLE(2) expands to ((2)+(2)), whereas if you had wrongly written #define DOUBLE (a) ((a)+(a)) then DOUBLE(2) would be expanded to (a) ((a)+(a))(2), resulting in a compile error.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | jogojapan |
| Solution 4 | Alexey Frunze |
| Solution 5 |
