C中宏的范围?

Vis*_*ath 28 c c-preprocessor

如何评估这些宏?

# define i 20
void fun();

int main(){
  printf("%d",i);
  fun();
  printf("%d",i);
  return 0;
}

void fun(){
  #undef i
  #define i 30
}
Run Code Online (Sandbox Code Playgroud)

提供输出为2020但是,

# define i 20
void fun(){
  #undef i
  #define i 30
}

int main(){
  printf("%d",i);
  fun();
  printf("%d",i);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出为3030.请解释.谢谢.

Voi*_*ter 55

无论函数调用如何,C预处理器都从上到下工作.无论宏定义的文件是什么,直到对应undef或直到翻译单元的末尾,从该点(行)开始是有效的.

那么,你的代码会变成,

# define i 20
               // from now on, all token i should become 20
void fun();
int main()
{
  printf("%d",i);   // printf("%d",20);
  fun();
  printf("%d",i);   // printf("%d",20);
  return 0;
}
void fun()
{
#undef i
              // from now on, forget token i
#define i 30
              // from now on, all token i should become 30
}
Run Code Online (Sandbox Code Playgroud)

你的第二个代码会变成,

# define i 20
               // from now on, all token i should become 20
void fun()
{
#undef i
               // from now on, forget i
#define i 30
               // from now on, all token i should become 30
}
int main()
{
  printf("%d",i);    //  printf("%d",30);
  fun();
  printf("%d",i);    // printf("%d",30);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,尽管其他答案断言_no scope_,但是C预处理器宏确实具有明确定义的范围,但该范围仅与预处理阶段相关,而不与任何其他转换阶段相关.该范围是"从定义点到当前翻译单元结束,或直到使用`#undefine`或使用`#define`重新定义宏未定义." (15认同)

Car*_*rum 18

根本没有涉及的范围.宏在预处理阶段单独处理,独立于编译阶段,没有C范围的概念.您的示例可以很容易:

#define i 20

void fun();

int main()
{
  printf("%d",i);
  fun();
  printf("%d",i);
  return 0;
}

void fun()
{
}

#undef i
#define i 30
Run Code Online (Sandbox Code Playgroud)

和:

#define i 20
#undef i
#define i 30

void fun()
{
}

int main()
{
  printf("%d",i);
  fun();
  printf("%d",i);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

你可以从中看出它的行为方式.


Mac*_*ade 7

根本没有范围.

宏由预处理器代替.因此,他们的扩张是由他们在源头中从上到下的位置来定义的.


Som*_*ude 6

预处理器宏没有范围,因为它们不是C语言的一部分.相反,它是一种在编译器正常运行之前运行的搜索替换程序.

预处理器只是通过任何文件,不必是C源文件,当它找到宏调用时,它只是将它替换为宏体中的文本.

  • 在C 2011第6.10.3节中,预处理器宏是C语言的一部分.是否单独执行预处理是一个实现细节; 一些编译器集成它. (3认同)

Kaz*_*Kaz 6

预处理程序符号绝对具有一个范围,但是该范围不会与其他范围(例如文件范围)交互。

预处理器符号作用域仅限于单个转换单元。一个#define在一个转换单元有另一个翻译单位上没有关系。

预处理程序符号的范围是该符号后面的指令之后的令牌区域#defines。此后,将根据控制规则识别并扩展宏的出现。预处理程序宏定义不是递归的。如果替换令牌序列包含正在定义的符号的调用,则不会这样识别。这就是为什么作用域在指令之后开始的原因。但是,当重新定义宏时,情况仍然如此。重新定义是特殊的,必须符合与原始定义相同的规则。(相同性的精确规则在标准中)。

预处理器符号的作用域以转换单元的末尾结束,如果受#undef指令限制,则更早。

因此,预处理器符号的范围本质上是翻译单元文本的区域,被视为预处理器令牌流,该符号可在其中进行识别和替换。