Incorrect Substitution of OpenMP Pragma in Macro Expansion - c

When an OpenMP pragma is used as part of an argument for a macro, it gets incorrectly substituted.
In this code:
#define make_body( ... ) { __VA_ARGS__ }
extern foo( int );
int main(){
make_body(
#pragma omp parallel for
for( int i = 0; i < 10; i += 1 ){
foo( i );
}
)
}
I would expect that it would be expanded to:
extern foo( int )
int main(){
{
#pragma omp parallel for
for( int i = 0; i < 10; i += 1 ){
foo( i );
}
}
}
However, (according to gcc -E) it becomes expanded to:
extern foo( int );
int main(){
#pragma omp parallel for
{
for( int i = 0; i < 10; i += 1 ){
foo( i );
}
}
}
Is this correct behavior?
How can I get the expected behavior, preferably without changing the arguments to the macro?
Does this happen with all pragmas?
Is this an effect of the variadic macro?
Do other compilers perform the same substitution?
Using gcc (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609

Is this correct behavior?
It would be most accurate to say that it is not incorrect behavior. The standard has this to say about macro arguments:
If there are sequences of preprocessing tokens within the list of arguments that would otherwise act as preprocessing directives, the behavior is undefined.
You have exercised that case, and accordingly reaped undefined behavior.
Does this happen with all pragmas? Is this an effect of the variadic macro? Do other compilers perform the same substitution?
The behavior is undefined, so it may vary among conforming implementations, and even within the same implementation, for any reason or none. I would guess that GCC is relatively consistent in this area, but in no way should you rely on that. It is not specifically tied to the macro involved being variadic.
How can I get the expected behavior, preferably without changing the arguments to the macro?
C11, which is supported by GCC 5, has a solution for the specific case of macros that emit pragmas: the _Pragma operator. It is more often used in literal macro replacement text, so that you can have a macro that represents a pragma, but it ought to work in a macro argument, too. You will, however, have to change the macro argument a bit:
make_body(
_Pragma("omp parallel for")
for( int i = 0; i < 10; i += 1 ){
foo( i );
}
)

You are not allowed to put any preprocessing directive inside the arguments to a function-like macro. (C11 6.10.3p11, last sentence.)
In this case, you should be able to write _Pragma("omp parallel for") and get the effect you want. Experimentation indicates that this works correctly with both clang and gcc (versions 7 and 8 respectively) but only if you specify -fopenmp on the command line. Yes, even if using -E.

Alternative solution this fixes a case we saw in real code which is way to big to be recreated here (not that we're exactly sure why it happens anyway).
-fopenmp is also necessary.
#define EMPTY()
#define DELAY(x) x EMPTY()
#define STRINGIZE(x) STRINGIZE_NO_PREPROCESS(x)
#define STRINGIZE_NO_PREPROCESS(x) #x
#define PRAGMA(x) _Pragma( STRINGIZE(x) )
#define DELAYED_PRAGMA_assist(x) PRAGMA(x)
#define DELAYED_PRAGMA DELAY(DELAYED_PRAGMA_assist)
#define PRAGMA_IN_MACRO_ARG(x) DELAYED_PRAGMA(x)
#define PRAGMA_IN_MACRO_BODY(x) PRAGMA(x)
PRAGMA_IN_MACRO_ARG can be used to correctly place a the pragma when the code is being passed to another macro as an argument
For example:
#define WRAP( body ) { body }
#define loop( i, N, body )\
if( N > 0 ) \
WRAP( \
PRAGMA_IN_MACRO_ARG(omp parallel for private(i)) \
for( i = 0; i < N; ++i ){ \
body \
} \
)
loop( i, 10, printf("%d\n", i); )
PRAGMA_IN_MACRO_BODY can be used to correctly place a the pragma when the code is simply part of a macro's body, and not as input to another macro
For example:
#define loop( i, N, body )\
if( N > 0 ) \
{\
PRAGMA_IN_MACRO_BODY(omp parallel for private(i)) \
for( i = 0; i < N; ++i ){ \
body \
} \
}
loop( i, 10, printf("%d\n", i); )

Related

Broken multi line macro

This multi line macro from the Nilorea library fails to compile when I include it in my C++ project. It is marked as extern "C".
Tried GodBolt, and the GCC 8.1 compiler barfs on the if statement in the following code : https://godbolt.org/z/Lq_7aT
#define Free( __ptr )\
if ( __ptr )\
{\
free( __ptr );\
__ptr = NULL;\
}
int* i = 0;
Free(i);
It should compile. Is this a matter of the standard in use?
I edited the question with a bad compilable example.
The Godbolt code fails to compile because
You are calling the code outside a function
You are attempting to assign to literal 0
You fail to include the necessary headers.
In addition, as noted in the comments, double underscore in identifiers is reserved for the implementation. The compiler doesn’t diagnose this but it’s illegal anyway.
When fixing these three issues, it works:
#include <stdlib.h>
#define Free(ptr) \
if (ptr) \
{ \
free(ptr); \
ptr = NULL; \
}
int main(void) {
int *px = NULL;
Free(px);
}
(I’ve also fixed the atrocious, inconsistent spacing.)

Why are some preprocessor macros not expanded unless they are arguments to another macro?

In certain situations, some token sequences are not preprocessed fully.
For example:
#define EMPTY()
#define DELAY(x) x EMPTY()
#define PRAGMA(args) _Pragma(args)
#define WRAP( BODY ) { BODY }
#define LOOP_Good( body, i, LB, UB ) \
WRAP( \
DELAY(PRAGMA)("omp parallel for") \
for( i = LB; i < UB; ++i ){ \
body \
} \
)
#define LOOP_Bad( body, i, LB, UB ) \
{ \
DELAY(PRAGMA)("omp parallel for") \
for( i = LB; i < UB; ++i ){ \
body \
} \
}
#define LOOP_Good_Again( body, i, LB, UB ) \
{ \
PRAGMA("omp parallel for") \
for( i = LB; i < UB; ++i ){ \
body \
} \
}
// Good
int i;
int lower_i = 0;
int upper_i = 10;
LOOP_Good( printf("%d\n", i);, i, lower_i, upper_i )
// Bad
LOOP_Bad( printf("%d\n", i);, i, lower_i, upper_i )
// Good again
LOOP_Good_Again( printf("%d\n", i);, i, lower_i, upper_i )
Which (using -E -fopenmp gcc 9.1) expands to the below (with formatting):
int i;
int lower_i = 0;
int upper_i = 10;
// Good
{
#pragma omp parallel for
for( i = lower_i; i < upper_i; ++i ){
printf("%d\n", i);
}
}
// Bad
{
PRAGMA ("omp parallel for")
for( i = lower_i; i < upper_i; ++i ){
printf("%d\n", i);
}
}
// Good again
{
#pragma omp parallel for
for( i = lower_i; i < upper_i; ++i ){
printf("%d\n", i);
}
}
In the 'good' case, the DELAY(PRAGMA) is expanded to PRAGMA which is then expanded (with the adjacent arguments) to _Pragma(...)
In the 'bad' case, the DELAY(PRAGMA) is expanded to PRAGMA but the processing stops and PRAGMA is left in the output.
If you take the 'bad' output and repreprocess it (with all the previously defined macros) it correctly expands.
The only difference is that the 'good' case, DELAY(PRAGMA) is part of the argument to the WRAP macro, where as the 'bad' case does not pass DELAY(PRAGMA) into any macro. If in the 'bad' case, we instead use PRAGMA alone, the problem is solved (as in the 'good again' case).
What's the reason for the different behaviors in the 'good' and 'bad' cases?
In the bad case, what you intend to be arguments to PRAGMA never appear with PRAGMA in tokens that are scanned for macro replacement.
We can ignore the LOOP_xxx macros; they just expand to various tokens without complications, and the resulting tokens are processed as if they appeared in the source file normally. We can instead consider just DELAY(PRAGMA)(foo) and WRAP(DELAY(PRAGMA)(foo).
Per C 2018 6.10.3.1 and 6.10.3.4, the arguments of a macro are processed for macro replacement, then the resulting tokens are substituted into the macro’s replacement tokens, then the resulting tokens and subsequent tokens of the source file are rescanned for further replacement. (When the tokens of a macro argument are being processed, they are treated as if they constitute the entire source file.)
In DELAY(PRAGMA)(foo):
PRAGMA is the argument x to DELAY, but it is not followed by parentheses, so it is not a macro to replace.
PRAGMA is substituted for x in DELAY’s replacement tokens x EMPTY().
The result, PRAGMA EMPTY(), is scanned for replacement.
EMPTY is replaced by nothing.
The results of the replacement of EMPTY, along with the subsequent tokens ((foo), and anything that follows it) are scanned. Note that PRAGMA is not in these tokens: It is not part of the tokens that resulted from replacing EMPTY.
Macro replacement is complete.
In WRAP(PRAGMA)(foo), the first five steps are the same, and the remaining steps result in replacement of PRAGMA (foo):
PRAGMA is the argument x to DELAY, but it is not followed by parentheses, so it is not a macro to replace.
PRAGMA is substituted for x in DELAY’s replacement tokens x EMPTY().
The result, PRAGMA EMPTY(), is scanned for replacement.
EMPTY is replaced by nothing.
The results of the replacement of EMPTY, along with the subsequent tokens ((foo)) are scanned. As above, PRAGMA is not in these tokens, so it is not replaced.
Macro replacement of the argument to WRAP is complete, having produced PRAGMA (foo).
These tokens from the argument are substituted into WRAP’s { BODY }, producing { PRAGMA (foo) }.
These tokens (along with following tokens in the source file) are rescanned for further replacement. Now PRAGMA (foo) appears in these tokens, so it is replaced.

Why am I getting the error "Expression Syntax" while executing the following C code:

#include<stdio.h>
#define PRINT(a,b) (while(a<b){printf("%d < %d\n",a,b); ++a;})
int main(void)
{
PRINT(1,5);
return 0;
}
I am getting a expression syntax error for the line PRINT(1,5);
The C compiler is seeing the code output from C language preprocessor. You can run the preprocessor directly to figure out which part of the processed code is the compiler having trouble with. Once you understand how the preprocessor works, you will be able to spot such errors without having to do this.
In my gnu gcc environment, cpp does the job:
% cpp <your source file name>
Will print lots of code but at the end, you will see
int main(void)
{
(while(1<5){printf("%d < %d\n",1,5); ++1;});
return 0;
}
Do you see what is wrong here? while statement is not an expression, so it cannot be enclosed in (). Next, ++1 is not allowed because 1=1+1 does not make sense. You need to use a variable.
You got explanation in comment why you get error. To get correct you can do this -
#define PRINT(a,b) \
for(int i=(a);i<(b);i++) \
{ \
printf("%d < %d\n",i,b); \
}
As "Cool Guy" said the compiler "sees" the values passed to the macro, as if you typed them out, not as variables, and definitely not as actual typed variables.
What you want is probably:
#define PRINT(a, b) int c=(a);while(c<(b)){printf("%d < %d\n", c, (b));++c;}
To make it clearer, though...
#define PRINT(a, b) \
int c = (a); \
\
while (c < (b)) { \
printf ("%d < %d\n", c, (b)); \
++c; \
}
This is assuming you actually need a while loop, though.
Otherwise use a for loop instead, it's easier, and cleaner.

How to implement a generic macro in C?

FUNC(param);
When param is char *,dispatch to func_string.
when it's int,dispatch to func_int
I think there may be a solution to this,as variable types are known at compile time..
This will be possible with C1X but not in the current standard.
It will look like this:
#define cbrt(X) _Generic((X), long double: cbrtl, \
default: cbrt, \
float: cbrtf)(X)
Variable types are known to the compiler, but not to the preprocessor (which sees the code simply as unstructured text a stream of tokens, and performs only simple replacement operations on it). So I am afraid you can't achieve this with C macros.
In C++, they invented templates to solve such problems (and more).
You can test for the characteristics of the types.
For example, int can hold a negative value, while char* can't. So if ((typeof(param))-1) < 0, param is unsigned:
if (((typeof(param))-1) < 0) {
do_something_with_int();
} else {
do_something_with_char_p();
}
The compiler obviously optimizes this out.
Try it here: http://ideone.com/et0v1
This would be even easier if the types had different sizes. For example, if you want to write a generic macro than can handle different character sizes:
if (sizeof(param) == sizeof(char)) {
/* ... */
} else if (sizeof(param) == sizeof(char16_t)) {
/* ... */
} else if (sizeof(param) == sizeof(char32_t)) {
/* ... */
} else {
assert("incompatible type" && 0);
}
GCC has a __builtin_types_compatible_p() builtin function that can check for types compatibility:
if (__builtin_types_compatible_p(typeof(param), int)) {
func_int(param);
} else if (__builtin_types_compatible_p(typeof(param), char*)) {
func_string(param);
}
Try it here: http://ideone.com/lEmYE
You can put this in a macro to achieve what you are trying to do:
#define FUNC(param) ({ \
if (__builtin_types_compatible_p(typeof(param), int)) { \
func_int(param); \
} else if (__builtin_types_compatible_p(typeof(param), char*)) { \
func_string(param); \
} \
})
(The ({...}) is a GCC's statement expression, it allows a group of statements to be a rvalue.
The __builtin_choose_expr() builtin can choose the expression to compile. With __builtin_types_compatible_p this allows to trigger an error at compile-time if the type of param is not compatible with both int and char*: (by compiling somehting invalid in this case)
#define FUNC(param) \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(param), int) \
, func_int(param) \
, __builtin_choose_expr(__builtin_types_compatible_p(typeof(param), char*) \
, func_string(param) \
, /* The void expression results in a compile-time error \
when assigning the result to something. */ \
((void)0) \
) \
)
This is actually a slightly modified example from __builtin_choose_expr docs.
There is no possibility to run time check types in C89 / ANSI C, but there is an extension to gcc which allows it. typeof or something along those lines if I remember. I saw it in the Linux Kernel once.
In kernel.h:
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; })
Take a look at this article: GCC hacks in the Linux kernel
When I first saw this I actually asked a question here on SO about:
min macro in kernel.h
I'm not quite sure exactly how you would use it to solve your problem, but it's something worth taking a look at.
You can't do this with a macro. Macro's value are substituted at compile time and are not intepreted. They are just substitutions.
Variable types are indeed known at compile time, however macro expansion takes place before compilation. I suggest you implement 2 overloaded functions instead of a macro.
my definition of a generic:
a structured abstract type which can only be fully defined with an input of other concrete types
this sounds exactly like a macro to me
pardon the psudo c code, my c is rusty
#include <stdio.h>
// todo: ret=self needs vec3##generic_t##_copy(self, ret);
// not to mention we should probably be using __builtin_add_overflow
// __builtin_add_overflow might actually itself be a reasonably generics method example
// please bear with me
#define GENERIC_VEC3_ADD(generic_t) \
generic_t vec3##generic_t##_add(generic_t self, generic_t other) {\
generic_t ret = self;\
ret[0] += other [0];;\
ret[1] += other [1];\
ret[2] += other [2];\
return ret;\
}
#define GENERIC_VEC3_FREPR(generic_t, printf_ts) \
int vec3##generic_t##_frepr(generic_t self, FILE fd)\
rerurn fprintf(fd, "<vec3##generic_t (##printf_ts##, printf_ts##, printf_ts##)>", \
self[0], self[1], self[2]);\
}
// here is the generic typedef, with some methods
#define GENERIC_VEC3(genetic_t, printf_ts) \
typedef vec3##generic_t generic_t[3];\
GENERIC_VEC3_ADD(generic_t) \
GENERIC_VEC3_FREPR(generic_t, printf_ts)
// later we decide what types we want this genic for
GENERIC_VEC3(int, %ul)
// and use our generic
int main()
{
vec3int foo = { 1, 2, 3 };;
vec3int bar = { 1, 2, 3 };;
vec3int sum = vec3int_add(foo, bar);
vec3int_frepr(sum, stderr);
fprintf(stderr, "\n");
exit EXIT_SUCCESS;
}

C Macro Question -(x) vs (-x)

I'm going through quiz answers from my professor and a question was:
the correct implementation of a function like macro for absolute value is:
#define abs(x) ((x)<0 ? (-x) : (x))
#define abs(x) ((x)<0 ? -(x) : (x))
Why is the second one correct vs the first one?
And why do you have to use all the (). Like what are the rules involved? Every variable needs a ()? Thanks.
There are various related problems that the extra parentheses solve. I'll go through them one by one:
Try: int y = abs( a ) + 2
Let's assume you use:
#define abs(x) (x<0)?-x:x
...
int y = abs( a ) + 2
This expands to int y = (a<0)?-a:a+2. The +2 binds only to the false result. 2 is only added when a is positive, not when it is negative. So we need parenthesis around the whole thing:
#define abs(x) ( (x<0) ? -x : x )
Try: int y = abs(a+b);
But then we might have int y = abs(a+b) which gets expanded to int y = ( (a+b<0) ? -a+b : a+b). If a + b is negative then b is not negated when they add for the result. So we need to put the x of -x in parentheses.
#define abs(x) ( (x<0) ? -(x) : x )
Try: int y = abs(a=b);
This ought to be legal (though bad), but it expands to int y = ( (a=b<0)?-(a=b):a=b ); which tries to assign the final b to the ternary. This should not compile. (Note that it does in C++. I had to compile it with gcc instead of g++ to see it fail to compile with the "invalid lvalue in assignment" error.)
#define abs(x) ( (x<0) ? -(x) : (x) )
Try: int y = abs((a<b)?a:b);
This expands to int y = ( ((a<b)?a:b<0) ? -((a<b)?a:b) : (a<b)?a:b ), which groups the <0 with the b, not the entire ternary as intended.
#define abs(x) ( ( (x) < 0) ? -(x) : (x) )
In the end, each instance of x is prone to some grouping problem that parentheses are needed to solve.
Common problem: operator precedence
The common thread in all of these is operator precedence: if you put an operator in your abs(...) invocation that has lower precedence then something around where x is used in the macro, then it will bind incorrectly. For instance, abs(a=b) will expand to a=b<0 which is the same as a=(b<0)... that isn't what the caller meant.
The "Right Way" to Implement abs
Of course, this is the wrong way to implement abs anyways... if you don't want to use the built in functions (and you should, because they will be optimized for whatever hardware you port to), then it should be an inline template (if using C++) for the same reasons mentioned when Meyers, Sutter, et al discuss re-implementing the min and max functions. (Other answers have also mentioned it: what happens with abs(x++)?)
Off the top of my head, a reasonable implementation might be:
template<typename T> inline const T abs(T const & x)
{
return ( x<0 ) ? -x : x;
}
Here it is okay to leave off the parentheses since we know that x is a single value, not some arbitrary expansion from a macro.
Better yet, as Chris Lutz pointed out in the comments below, you can use template specialization to call the optimized versions (abs, fabs, labs) and get all the benefits of type safety, support for non-builtin types, and performance.
Test Code
#if 0
gcc $0 -g -ansi -std=c99 -o exe && ./exe
exit
#endif
#include <stdio.h>
#define abs1(x) (x<0)?-x:x
#define abs2(x) ((x<0)?-x:x)
#define abs3(x) ((x<0)?-(x):x)
#define abs4(x) ((x<0)?-(x):(x))
#define abs5(x) (((x)<0)?-(x):(x))
#define test(x) printf("//%30s=%d\n", #x, x);
#define testt(t,x) printf("//%15s%15s=%d\n", t, #x, x);
int main()
{
test(abs1( 1)+2)
test(abs1(-1)+2)
// abs1( 1)+2=3
// abs1(-1)+2=1
test(abs2( 1+2))
test(abs2(-1-2))
// abs2( 1+2)=3
// abs2(-1-2)=-1
int a,b;
//b = 1; testt("b= 1; ", abs3(a=b))
//b = -1; testt("b=-1; ", abs3(a=b))
// When compiled with -ansi -std=c99 options, this gives the errors:
//./so1a.c: In function 'main':
//./so1a.c:34: error: invalid lvalue in assignment
//./so1a.c:35: error: invalid lvalue in assignment
// Abs of the smaller of a and b. Should be one or two.
a=1; b=2; testt("a=1; b=2; ", abs4((a<b)?a:b))
a=2; b=1; testt("a=2; b=1; ", abs4((a<b)?a:b))
// abs4((a<b)?a:b)=-1
// abs4((a<b)?a:b)=1
test(abs5( 1)+2)
test(abs5(-1)+2)
test(abs5( 1+2))
test(abs5(-1-2))
b = 1; testt("b= 1; ", abs5(a=b))
b = -1; testt("b=-1; ", abs5(a=b))
a=1; b=2; testt("a=1; b=2; ", abs5((a<b)?a:b))
a=2; b=1; testt("a=2; b=1; ", abs5((a<b)?a:b))
}
Output
abs1( 1)+2=3
abs1(-1)+2=1
abs2( 1+2)=3
abs2(-1-2)=-1
a=1; b=2; abs4((a<b)?a:b)=-1
a=2; b=1; abs4((a<b)?a:b)=1
abs5( 1)+2=3
abs5(-1)+2=3
abs5( 1+2)=3
abs5(-1-2)=3
b= 1; abs5(a=b)=1
b=-1; abs5(a=b)=1
a=1; b=2; abs5((a<b)?a:b)=1
a=2; b=1; abs5((a<b)?a:b)=1
Yes, every variable needs parenthesis around it directly.
The reason is because you can pass things into the macro that aren't "nice", like arithmetic expressions or really any expression that isn't a single variable. It should be easy to see that with abs(1+2), the expanded -(1 + 2) will give a different result than (-1 + 2). This is why -(x) is more correct.
Unfortunately neither macro is safe, you should use an inline function for things like this instead. Consider:
abs (x++); // expands to ((x++) < 0 ? - (x++) : (x++))
This is clearly wrong with the macro, but it would work correctly if an inline function was used instead.
There are other problems with using macros instead of functions as well. See this question.
Edit: Noting that the question is about C, inline functions may only be available in C99.

Resources