ATOMIC_JOIN(prefix, detail_platform) is an macro which will output some string as follows:
base/atomic/gcc_gnu_x64
in another macro ATOMIC_DETAIL_HEADER, which output expected to be:
"base/atomic/gcc_gnu_x64.hpp" // notice: double quotes included in the output
I try to write the ATOMIC_DETAIL_HEADER, such as:
#define ATOMIC_DETAIL_HEADER(prefix) "ATOMIC_JOIN(prefix, ATOMIC_DETAIL_PLATFORM).hpp"
#define ATOMIC_DETAIL_HEADER(prefix) \"ATOMIC_JOIN(prefix, ATOMIC_DETAIL_PLATFORM).hpp\"
#define ATOMIC_DETAIL_HEADER(prefix) "##ATOMIC_JOIN(prefix, ATOMIC_DETAIL_PLATFORM).hpp##"
... failed!
but if i hope output is:
<base/atomic/gcc_gnu_x64.hpp>
The follow macro define can do right thing:
#define ATOMIC_DETAIL_HEADER(prefix) <ATOMIC_JOIN(prefix, ATOMIC_DETAIL_PLATFORM).hpp>
A cpp macro cannot build strings this way. It can join tokens to form new tokens, but at every stage it must be a valid token. Your example with angle-brackets works because the bracket characters are distinct tokens whereas the double-quotes cannot exist floating-off like that, and you cannot apply ## to it.
In most contexts, the compiler will concatenate adjacent string literals, so it may be sufficient to #stringify each piece at let the compiler do that.
While luser droog correctly stated why your use of quotes didn't work, he didn't show exactly how the goal can be accomplished. Indeed the # operator replaces a parameter by a string literal, i. e. puts quotation marks around the argument. This is slightly complicated by the fact that your token sequence has to be expanded first, so an additional level of macro substitution is needed:
#define QUOTED(a) #a
#define QUOTE(a) QUOTED(a)
#define ATOMIC_DETAIL_HEADER(prefix) QUOTE(ATOMIC_JOIN(prefix, ATOMIC_DETAIL_PLATFORM).hpp)
Related
I have a #define'd value named HEIGHT with a value of 20.
I want to use the ASCI escape code "\033[HA" (where H is the number of lines the cursor is moved up.
However, when my code reads "\033[HEIGHTA", it is reading the 'H' as a different escape code (return cursor home). How can I include a #define'd value within an escape code?
Thanks
There are several alternatives, among them
Use a function instead of a macro to generate the escape code as needed. For example,
const char *cursor_up_seq() {
static char sequence[12];
if (sequence[0] == '\0') {
// one-time initialization
sprintf(sequence, "\033[%dA", HEIGHT);
}
return sequence;
}
As a variation on (1), do not produce the escape sequence as a standalone entity at all. Instead, embed it in whatever else you are printing, where it is natural to use (say) printf() to print the value of the HEIGHT macro.
But if you really want to produce a macro for a string literal containing the whole escape sequence, then you can do so by combining two C features:
the stringification (#) macro operator, and
automatic concatenation of adjacent string literals
Another answer, now deleted, attempted to demonstrate that, but floundered on one of the gotchas in that area. Here is a variation that works:
#define HEIGHT 20
#define STRINGIFY(x) #x
#define STRINGIFY_VALUE(x) STRINGIFY(x)
#define SEQUENCE "\033[" STRINGIFY_VALUE(HEIGHT) "A"
The resulting SEQUENCE macro expands to "\033[" "20" "A", which is 100% equivalent to "\033[20A" because of string literal concatenation. The gotcha here is that you cannot use STRINGIFY() directly for this purpose, because that does not macro-expand its argument before converting it to a string (per the standard behavior of #). Wrapping it in another macro layer (STRINGIFY_VALUE) results in that outer layer expanding the argument before presenting the result for stringification.
C seems to be pretty permissive when it comes to whitespace.
We can use or omit whitespace around an operator, between a function name and its parenthesized list of arguments, between an array name and its index, etc. in order to make code more readable. I understand this is a matter of preference.
The only place I can think of where whitespace is NOT allowed is this:
#include < stdio.h > // fatal error: stdio.h : No such file or directory
What are the other contexts in C where whitespace cannot be used for readability?
In most cases, adding whitespace within a single token either makes the program invalid or changes the meaning of the token. An obvious example: "foo" and " foo " are both valid string literals with different values, because a string literal is a single token. Changing 123456 to 123 456 changes it from a single integer constant to two integer constants, resulting in a syntax error.
The exceptions to this involve the preprocessor.
You've already mentioned the #include directive. Note that given:
#include "header.h"
the "header.h" is not syntactically a string literal; it's processed before string literals are meaningful. The syntax is similar, but for example a \t sequence in a header name isn't necessarily replaced by a tab character.
Newlines (which are a form of whitespace) are significant in preprocessor directives; you can't legally write:
#ifdef
FOO
/* ... */
#endif
But whitespace other than newlines is permitted:
# if SPACES_ARE_ALLOWED_HERE
#endif
And there's one case I can think of where whitespace is permitted between preprocessor tokens but it changes the meaning. In the definition of a function-like macro, the ( that introduces the parameter list must immediately follow the macro name. This:
#define TWICE(x) ((x) + (x))
defines TWICE as a function-like macro that takes one argument. But this:
#define NOT_TWICE (x) ((x) + (x))
defines NOT_TWICE as an ordinary macro with no arguments that expands to (x) ((x) + (x)).
This rule applies only to macro definitions; a macro invocation follows the normal rules, so you can write either TWICE(42) or TWICE ( 42 ).
White spaces are not allowed for readability (are significant) within a lexical token. I.e. within an identifier (foo bar is different from foobar), within a number (123 456 is different from 123456), within a string (that's your example basically) or within an operator (+ + is different from ++ and + = is different from +=). Between those you can add as much white space as you want, but when you add white space inside such a token you will break the lexical token into two separate tokens (or change the value in case of string constants), thus changing the meaning of your code .
In most cases the code with the added white space is either equivalent to the original code or results in a syntax error. But there are exceptions. For example:
return a +++ b;
is the same as
return a ++ + b;
but is different from:
return a + ++ b;
As I recall you need to be very careful with function-like macros, as in such dummy example:
#include <stdio.h>
#define sum(x, y) ((x)+(y))
int main(void)
{
printf("%d\n", sum(2, 2));
return 0;
}
the:
#define sum(x, y) ((x)+(y))
is different thing than say:
#define sum (x, y) ((x)+(y))
The latter one is object-like macro, that replaces exactly with (x, y) ((x)+(y)), that is parameters are not being subsituted (as it happens in function-like macro).
I came across one more piece of code that is even more confusing..
#include "stdio.h"
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
int main(void)
{
printf("%s\n",h(f(1,2)));
printf("%s\n",g(1));
printf("%s\n",g(f(1,2)));
return 0;
}
output is
12
1
f(1,2)
My assumption was
1) first f(1,2) is replaced by 12 , because of macro f(a,b)
concantenates its arguments
2) then g(a) macro replaces 1 by a string literal "1"
3) the output should be 1
But why is g(f(1,2)) not getting substituted to 12.
I'm sure i'm missing something here.
Can someone explain me this program ?
Macro replacement occurs from the outside in. (Strictly speaking, the preprocessor is required to behave as though it replaces macros one at a time, starting from the beginning of the file and restarting after each replacement.)
The standard (C99 §6.10.3.2/2) says
If, in the replacement list, a parameter is immediately preceded by a # preprocessing
token, both are replaced by a single character string literal preprocessing token that
contains the spelling of the preprocessing token sequence for the corresponding
argument.
Since # is present in the replacement list for the macro g, the argument f(1,2) is converted to a string immediately, and the result is "f(1,2)".
On the other hand, in h(f(1,2)), since the replacement list doesn't contain #, §6.10.3.1/1 applies,
After the arguments for the invocation of a function-like macro have been identified,
argument substitution takes place. A parameter in the replacement list, unless preceded
by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is
replaced by the corresponding argument after all macros contained therein have been
expanded.
and the argument f(1, 2) is macro expanded to give 12, so the result is g(12) which then becomes "12" when the file is "re-scanned".
Macros can't expand into preprocessing directives. From C99 6.10.3.4/3 "Rescanning and further replacement":
The resulting completely macro-replaced preprocessing token sequence
is not processed as a preprocessing directive even if it resembles
one,
Source: https://stackoverflow.com/a/2429368/2591612
But you can call f(a,b) from g like you did with h. f(a,b) is interpreted as a string literal as #Red Alert states.
I am trying to do the following:
#define mkstr(str) #str
#define cat(x,y) mkstr(x ## y)
int main()
{
puts(cat(\,n));
puts(cat(\,t))
return 0;
}
both of the puts statements cause error. As \n and n both are preprocessor tokens I expected output them correctly in those puts statements, but Bloodshed/DevC++ compiler giving me the following error:
24:1 G:\BIN\cLang\macro2.cpp pasting "\" and "n" does not give a valid preprocessing token
Where is the fact I'm missing?
The preprocessor uses a tokenizer which will require C-ish input. So even when stringifying you cannot pass random garbage to a macro. ==> Don't make your preprocessor sad - it will eat kittens if you do so too often.
Actually, there is no way to create "\n" via compile-time concatenation since "\\" "n" is a string consisting of the two literals, i.e. "\n".
I am defining a macro that evaluates to a constant string, holding the filename and the line number, for logging purposes.
It works fine, but I just can't figure out why 2 additional macros are needed - STRINGIFY and TOSTRING, when intuition suggests simply __FILE__ ":" #__LINE__.
#include <stdio.h>
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define THIS_ORIGIN (__FILE__ ":" TOSTRING(__LINE__))
int main (void) {
/* correctly prints "test.c:9" */
printf("%s", THIS_ORIGIN);
return 0;
}
This just seems like an ugly hack to me.
Can someone explain in detail what happens stage by stage so that __LINE__ is stringified correctly, and why neither of __FILE__ ":" STRINGIFY(__LINE__) and __FILE__ ":" #__LINE__ works?
Because of the order of expansion. The GCC documentation says:
Macro arguments are completely macro-expanded before they are substituted into a macro body, unless they are stringified or pasted with other tokens. After substitution, the entire macro body, including the substituted arguments, is scanned again for macros to be expanded. The result is that the arguments are scanned twice to expand macro calls in them.
So if the argument will be stringified, it is not expanded first. You are getting the literal text in the parenthesis. But if it's being passed to another macro, it is expanded. Therefore if you want to expand it, you need two levels of macros.
This is done because there are cases where you do not want to expand the argument before stringification, most common being the assert() macro. If you write:
assert(MIN(width, height) >= 240);
you want the message to be:
Assertion MIN(width, height) >= 240 failed
and not some insane thing the MIN macro expands to (in gcc it uses several gcc-specific extensions and is quite long IIRC).
You can't simply use __FILE__":"#__LINE__ because the stringify operator # can only be applied to a macro parameter.
__FILE__ ":" STRINGIFY(__LINE__) would work OK with other text (eg __FILE__ ":" STRINGIFY(foo), but doesn't work when used with another macro (which is all __LINE__ really is) as the parameter; otherwise that macro doesn't get substituted.