does #define foo 1 ## ## 2 cause undefined behaviour? - c

6.10.3.3 of the c11 spec says
each instance of a ## preprocessing token in the replacement list (not from an argument) is deleted and the preceding preprocessing token is concatenated with the following preprocessing token. [...] If the result is not a valid preprocessing token, the behavior is undefined.
So 1 ## ## would be replaced with 1##, which is not a valid preprocessing token, so the behaviour is undefined.
Is that correct?
#include <stdio.h>
int main()
{
#define foo 1 ## ## 2
printf("%d\n", foo);
return 0;
}
Compiling the above with gcc -std=c11 -Wall -Wpedantic doesn't give any warnings, and the output is 12 as if there were only one ##. Is that the expected output?

Related

C Macro with _Pragma fails to compile

I'm trying to define a macro to return the result of a range check which works on signed and unsigned types. However, because I am compiling with -Wextra which includes -Wtype-limits, I want to ignore -Wtype-limits just for this macro. Unfortunately, this:
#define IN_RANGE(v, min, max) \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
( (((v) < (max)) && ((v) > (min))) ? true : false ) \
_Pragma("GCC diagnostic pop")
Fails to compile (because I'm also using -Werror) with:
... error: expected expression before '#pragma'
[build] 40 | _Pragma("GCC diagnostic push") \
[build] | ^~~~~~~
Edit: here's a complete example.
#include <stdio.h>
#include <stdint.h>
#define IN_RANGE(v, min, max) \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
( (((v) < (max)) && ((v) > (min))) ? true : false ) \
_Pragma("GCC diagnostic pop")
const uint32_t MIN_NUM = 0;
const uint32_t MAX_NUM = 10;
int main() {
printf("%s", IN_RANGE(8, MIN_NUM, MAX_NUM) ? "OK": "FAIL");
return 0;
}
Fails with (on gcc 9):
$ gcc -Wall -Wextra example.c
example.c: In function ‘main’:
example.c:14:1: error: expected expression before ‘#pragma’
14 | printf("%s", IN_RANGE(8, MIN_NUM, MAX_NUM) ? "OK": "FAIL");
| ^ ~
Given some experimentation, it seems that you can't just embed the _Pragma() operator in the middle of an expression. In effect, it needs to be used where a statement can be used.
This code compiles, and AFAICT it is because there's a complete statement sandwiched between the _Pragma() operators:
#include <stdbool.h>
#include <stdio.h>
#define IN_RANGE2(r, v, min, max) \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
((r) = (((v) < (max)) && ((v) > (min)))); \
_Pragma("GCC diagnostic pop")
int main(void)
{
int x = 10;
bool y;
IN_RANGE2(y, x, -9, +9);
printf("%d\n", y);
return 0;
}
Note the semicolon before the third _Pragma() operator. Without that, I was getting expected ‘;’ before ‘#pragma’ (as an error since I too compile with -Werror).
I've also simplified the conditional so it doesn't use the ternary operator, as I noted in a comment.
The relevant section of the standard is §6.10.9 Pragma operator. It says:
A unary operator expression of the form:
_Pragma ( string-literal )
is processed as follows: The string literal is destringized by deleting any encoding prefix, deleting the leading and trailing double-quotes, replacing each escape sequence \" by a double-quote, and replacing each escape sequence \\ by a single backslash. The resulting sequence of characters is processed through translation phase 3 to produce preprocessing tokens that are executed as if they were the pp-tokens in a pragma directive. The original four preprocessing tokens in the unary operator expression are removed.
Think about what the code expands to in your example:
int main(void)
{
printf("%s", IN_RANGE(8, MIN_NUM, MAX_NUM) ? "OK": "FAIL");
return 0;
}
is approximately equivalent to:
/* SO 7548-0114 */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
const uint32_t MIN_NUM = 0;
const uint32_t MAX_NUM = 10;
int main(void)
{
printf("%s",
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
((((8) < (MAX_NUM)) || (8) > (MIN_NUM)) ? true : false)
#pragma GCC diagnostic push
? "OK": "FAIL");
return 0;
}
This doesn't compile. It produces the error:
pragma67.c: In function ‘main’:
pragma67.c:12:11: error: expected expression before ‘#pragma’
12 | #pragma GCC diagnostic push
| ^~~
Line 12 is the first #pragma directive.
I'm not totally convinced that this is what the standard mandates, but it is what I get from GCC 11.2.0.
However, when I compile with Apple's Clang (Apple clang version 14.0.0 (clang-1400.0.29.202)), both versions of the code I show compile OK. Thus, there is a discrepancy in the interpretation of the standard between these two major C compilers.
And, indeed, when I compile with Clang, your original code compiles cleanly. You can probably make a case out for a bug report to the GCC team. However, if you're going to write portable code, you'll need to accept the limitations imposed by GCC for a few years yet (though that depends on your portability requirements).

C++ preprocessor ## operator

What is wrong? I would like the xconcat line to work.
#define concat(a,b) a ## b
#define xconcat(a,b) concat(a,b)
int main() {
xconcat(xconcat(boost::variant<,int), >) y;
boost::variant<int> x;
return 0;
}
g++ -E x.cpp
# 1 "x.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "x.cpp"
int main() {
x.cpp:5:1: error: pasting "<" and "int" does not give a valid preprocessing token
x.cpp:5:1: error: pasting "int" and ">" does not give a valid preprocessing token
boost::variant<int > y;
boost::variant<int> x;
return 0;
}
The token pasting operator technically can't be used to paste something that doesn't end up being a token. GCC enforces that restriction, while some other compilers don't (the ## operator just seems to perform basic concatenation of the strings which then gets tokenized later).
From C++11 16.3.3/3 "The ## operator":
If the result is not a valid preprocessing token, the behavior is undefined.
The same language is in pretty much every C and C++ standard going back to C90.
In your case you don't need to use token pasting since you're dealing with separate tokens anyway:
#define yyconcat(a,b) a b
#define yconcat(a,b) yyconcat(a,b)
int main() {
yconcat(yconcat(boost::variant<,int), >) y;
boost::variant<int> x;
return 0;
}
g++ -E so-test.c
C:\so-test>g++ -E so-test.c
# 1 "so-test.c"
# 1 "<command-line>"
# 1 "so-test.c"
int main() {
boost::variant< int > y;
boost::variant<int> x;
return 0;
}

C preprocessor tokenization does not expand macro?

1) Why is the macro MSG not expanded in the following expression?
#define MSG Hello
#define HELLO(name) MSG ## name
void HELLO(Dave) () {}
Using
gcc -E -P test.cpp
Output:
void MSGDave () {}
MSG name expands to Hello Dave. And MSG # name expands to Hello "Dave". So what causes gcc not to expand MSG ## name?
2) Is there a workaround?
Is there a preprocessor directive like defined(x), such as expand(x)?
Because macro arguments are not substituted when preceded or followed by a ## operator.
C11 §6.10.3.1 Argument substitution
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. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.
#define MSG Hello
#define cat(x, y) x ## y
#define cat2(x, y) cat(x, y)
#define HELLO(name) cat2(MSG,name)
Live demo # ideone.

C compiling error: stray '##' in program

I was working with an embedded kernel source when I saw something like this:
#define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, clksrc_nr, clksrc_src) \
static void __init omap##name##_timer_init(void) \
{ \
omap2_gp_clockevent_init((clkev_nr), clkev_src); \
omap2_gp_clocksource_init((clksrc_nr), clksrc_src); \
}
and when I tryed to make a program that used this ## thing (that I don't know the name) to see what it could really do I didn't got it to work. Below is what I did to test it's function. I just want to see if the argument inside the ## is literal or not, but something is clearly missing in my code for it to compile...
#include <stdio.h>
#include <stdlib.h>
#define DEFINE_1 2
#define DEFINE_2 4
#define DEFINE_3 6
#define DEFINE_i 9
int main(void)
{
int i;
for(i=1;i<4;i++) {
printf("numero %d = %d\n",i,DEFINE_##i##);
}
return EXIT_SUCCESS;
}
The output of gcc is:
test.c: In function ‘main’:
test.c:14:5: error: stray ‘##’ in program
test.c:14:33: error: ‘DEFINE_’ undeclared (first use in this function)
test.c:14:33: note: each undeclared identifier is reported only once for each function it appears in
test.c:14:42: error: expected ‘)’ before ‘i’
test.c:14:42: error: stray ‘##’ in program
Anyone knows what is wrong? Thanks
It's the token concatenation operator for the C preprocessor. The reason your example doesn't compile is because you're not using the ## operator within a macro (i.e. #define statement).
Here's another post with some more information.
## means concatenation at time of preprocessing.
http://gcc.gnu.org/onlinedocs/cpp/Concatenation.html
You can use ## in the preprocessor directives only.
## is used for concatenation in C preprocessor macros.
In your example, the idea is to concatenate omap with the function name. For example
OMAP_SYS_TIMER_INIT(foo, ...)
will create a function named omapfoo.
## is token pasting operator and you can only use it in a macro definition. You cannot use it outside a macro definition.
Maybe what you are trying to do is, DEFINE_ and (i=1) will concatenate using ## to form "DEFINE_1" and that will be your macro with value 2. Right? If that's the case, the problem is that, macro is preprocessor and value will be get in lined before execution. So it looks for DEFINE_i and there is no such macro. Keep it in mind i=1,2,3.. and so on during runtime.

Preprocessor macro GCC: pasting x and x does not give a valid preprocessing token

#define PATH "yagh/headers/"
#define FILNAME "includefile"
#define CONCAT(a__, b__) CONCAT_DO(a__, b__)
#define CONCAT_DO(a__, b__) a__##b__
#define CONCATTHREE(a__, b__, c__) CONCAT(CONCAT(a__, b__), c__)
#define STRINGIFY(a__) #a__
#include STRINGIFY(CONCATTHREE(PATH ,FILNAME ,.h));
This macro works fine in VS compiler but does not compile on GCC compiler:
Error: error: pasting "/" and "includefile" does not give a valid preprocessing token
and for some include files it gives the error:
Error: pasting "includefile" and "." does not give a valid preprocessing token
GCC is being a bit stricter in enforcing the C standard: see Differences in Macro ## concatenation operator between Visual-C++ and gcc and http://gcc.gnu.org/onlinedocs/gcc-4.3.3/cpp/Concatenation.html#Concatenation.
You might try #include STRINGIFY(PATH FILNAME.h) (the lack of space between FILNAME and .h is important) -- that works for me with gcc 4.6.3.

Resources