在某些情况下,某些令牌序列未得到充分预处理。例如:
#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 )
哪个(使用-E -fopenmp
gcc 9.1)扩展到以下内容(带有格式):
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);
}
}
在“好”情况下,将DELAY(PRAGMA)
扩展到PRAGMA
,然后再扩展(使用相邻的参数)为_Pragma(...)
在“不良”情况下,将DELAY(PRAGMA)
扩展为,PRAGMA
但处理停止并PRAGMA
留在输出中。如果采用“不良”输出并对其进行预处理(使用所有先前定义的宏),则该输出会正确扩展。
唯一的区别是“好”情况DELAY(PRAGMA)
是WRAP
宏参数的一部分,而“坏”情况不会传递DELAY(PRAGMA)
给任何宏。如果在“不好”的情况下,我们改为PRAGMA
单独使用,则问题得到解决(如在“再次好”的情况下)。
在“好”和“坏”情况下,不同行为的原因是什么?
在最坏的情况下,您打算成为参数的参数将PRAGMA
永远不会出现PRAGMA
在扫描以替换宏的令牌中。
我们可以忽略LOOP_xxx
宏。它们只是扩展为各种令牌而没有复杂性,并且处理所得的令牌就像它们正常出现在源文件中一样。相反,我们可以考虑公正DELAY(PRAGMA)(foo)
和WRAP(DELAY(PRAGMA)(foo)
。
根据C 2018 6.10.3.1和6.10.3.4,处理宏的参数以进行宏替换,然后将结果标记替换为宏的替换标记,然后重新扫描结果标记和源文件的后续标记以进行进一步替换。(在处理宏参数的标记时,将它们视为构成了整个源文件。)
在DELAY(PRAGMA)(foo)
:
PRAGMA
为参数x
来DELAY
,但后面没有括号,所以它不是一个宏替换。PRAGMA
被替换为x
inDELAY
的替换令牌x EMPTY()
。PRAGMA EMPTY()
扫描结果进行替换。(foo)
扫描EMPTY的替换结果以及随后的标记(和之后的所有标记)。请注意,PRAGMA
是不是在这些令牌:这是不是源于更换令牌的一部分EMPTY
。在中WRAP(PRAGMA)(foo)
,前五个步骤相同,其余步骤导致替换PRAGMA (foo)
:
PRAGMA
为参数x
来DELAY
,但后面没有括号,所以它不是一个宏替换。PRAGMA
被替换为x
inDELAY
的替换令牌x EMPTY()
。PRAGMA EMPTY()
扫描结果进行替换。(foo)
扫描EMPTY的替换结果以及随后的标记()。如上所述,PRAGMA
这些令牌中没有,因此不会被替换。WRAP
已完成PRAGMA (foo)
。WRAP
的{ BODY }
产生{ PRAGMA (foo) }
。PRAGMA (foo)
出现在这些标记中,因此将其替换。本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句