Oziphantom wrote: ↑Sat Nov 23, 2019 8:25 am
the argument tokens are examined for macro calls, and expanded as necessary, just before insertion
This is what you are seeing and what you would expect.. however the bit of text before it
Unless the parameter in there placement sequence is preceded by #, or preceded or followed by ##,
which is what puts this case into "open for interpretation".
As far as I see this, this isn't open to interpretation. Yes, the text says "unless [it's] preceded or followed by ##".
However, the "unless" doesn't mean: "The parameters are expanded before insertion, unless they have ##, in which case they can also be expanded during the macro declaration instead of the macro call."
This is not what they're saying. They say "unless" because # and ## have additional rules, which is explained in the next paragraph:
Second, if the definition token sequence for either kind of macro contains a ## operator, then just after replacement of the parameters, each ## is deleted, together with any white space on either side, so as to concatenate the adjacent tokens and form a new token.
So, it merely says: "Macro parameters are expanded before insertion, unless they have # or ##. In this case, they have additional stuff done with them."
But it doesn't mean: "Macro parameters are expanded before insertion, unless they have # or ##. In this case, the parameters are already parsed and interpreted in the line where the macro gets defined."
Especially since we're not even talking about a parameter here: CurrentPostfix in my examples isn't a macro parameter that's passed in the parentheses, it's a global part of the macro itself, so it refers even less to the described exceptions.
Oziphantom wrote: ↑Sat Nov 23, 2019 8:25 am
note the
The effect is undefined if invalid tokens are produced, or if the result depends on the order of processing of the ## operators
Sure, there might be undefined behavior in there if you create some bizarre stuff. For example, if you call a macro and one of the parameters is a macro itself:
After
#define cat(x, y) x ## y
the call cat(var, 123) yields var123. However, the call cat(cat(1,2),3) is undefined: the presence of ## prevents the arguments of the outer call from being expanded. Thus it produces the token string
cat ( 1 , 2 )3
and )3 (the catenation of the last token of the first argument with the first token of the second) is not a legal token.
Again, the undefined behavior refers to some really strange stuff that you might try to do during a macro call.
But at no point ever in this whole paragraph does the text even slightly allude to the idea that the macro tokens might be interpreted at definition time instead of usage time. Especially since, as I said, my CurrentPostfix isn't even a macro
parameter, but just something that's used inside the macro globally.
So, no, the paragraph doesn't say anything about the idea that the preprocessor might turn this:
Code: Select all
#define CurrentArea A
#define MACRO(name) name##CurrentArea
into this:
Code: Select all
#define CurrentArea A
#define MACRO(name) name##A
There's nothing that even
hints at the idea that macro contents are expanded in the line where the #define resides.
The undefined behavior examples all refer to strange situations when you
call the macro.
Oziphantom wrote: ↑Sat Nov 23, 2019 8:25 am
So it neither says what I say, and neither says what you say which is my point.
Well, it does say that macro parameters are expanded at call time, but never says that they are expanded at #define time.
And this counts even more for stuff that's in the macro but that's not in the parameter list.
Hence, CurrentArea will, if at all, only be replaced whenever the macro is called.
So, you can define and redefine CurrentArea multiple times and the macro calls will always use the current value.
The idea that the macro definition itself transforms CurrentArea immediately, so every macro call always has the replacement of what CurrentArea happened to be at the moment of the macro definition, this is totally not what the paragraph in that book was talking about.
Oziphantom wrote: ↑Sat Nov 23, 2019 8:25 am
A classic case where macros don't always do what you think they should do is the __FILE__ and __LINE__ "extensions", you want them to show you the file and line where you call the macro, but unless you actually put them in on said line, you end up with the file and line the macro was originally defined on and not the line it was called on.
some file #define LOG_THIS(x) LOG(X,__FILE__,__LINE__)
in another file
LOG_THIS("Something happened")
gives you MACROS.H:120 Something happened
LOG_THIS("Something happened",__FILE__,__LINE__)
Myfile.m:325 Something happened
Sorry, but that's wrong.
Unfortunately, I cannot try out your example myself since you never gave me the LOG macro.
But this program:
Code: Select all
#include <stdio.h>
#include <conio.h>
#define LOG(text, formatParameter) printf(text, formatParameter)
#define LOG_THIS() LOG("Current line: %i\n", __LINE__)
int main(void)
{
LOG_THIS();
LOG_THIS();
getch();
return 0;
}
outputs
Current line: 8
Current line: 9
and not
Current line: 5
Current line: 5
Same when I put the LOG macro into a header file and use the __FILE__ macro: It gives me the file name of my C file. Even if the LOG macro in the header file uses the __FILE__ macro itself:
Code: Select all
Macros.h:
#define LOG(text) printf(text, __FILE__)
Main.c:
#define LOG_THIS() LOG("Current file: %s\n")
Output:
Main.c
Such an example is even used on websites:
https://www.cprogramming.com/reference/ ... INE__.html
Code: Select all
int logError (int line, const std::string& message)
{
cerr << "[" << line << "]" << message << endl;
}
#define LOG( message ) logError( __LINE__, message )
// LOG can now be used to produce a log message that includes the line on which the log occurrred
I don't know where you got your interpretations from.
So, if you can create a minimalistic compilable example where __FILE__ and __LINE__ behave the way you say and tell me which compiler you used, then I can check it out.
Otherwise, I cannot just take your word for it if actual compilers produce a different result from what you're claiming.