为什么将字符串运算符仅接受为宏?

时间:2019-04-11 15:56:53

标签: c c-preprocessor language-lawyer

我尝试在代码中使用#运算符:

#include <stdio.h>

int main(void)
{
    printf("hello %s !!! n", #world);
    return 0;
}

使用gcc编译后,此代码会产生以下错误:

str.c: In function ‘main’:
str.c:5:27: error: stray ‘#’ in program
  printf("hello %s !!! n", #world);

但是,当我定义使用此运算符的宏时,代码将被编译:

#include <stdio.h>

#define STRINGIFY(x) #x

int main(void)
{
    printf("hello %s \n", STRINGIFY(world));
    return 0;
}

预处理程序是否报告了此错误?如果是这样,为什么?

2 个答案:

答案 0 :(得分:3)

因为#parameter扩展的一部分。所有这些都是在编译器甚至没有看到代码之前就由预处理器完成的。并且此令牌仅应用于宏参数。 考虑以下宏:

#define STR(x) #x

Str(Hello)"Hello"

但是,如果我们在代码中编写#word,则预处理器不会将其视为宏的一部分,并且 word 不是宏参数。因此,预处理器将忽略它。编译器看到相同的#word,却不知道该怎么做。因此它报告一个错误。考虑下面的预处理器文本。

#define STR(x) #x
const char * str=STR(Hello);
const char * buggy_str=#Hello;

结果将是:

const char * str="Hello";
const char * buggy_str=#Hello;

C编译器看到第一个字符串,对他来说还可以。但是,当他看到第二个字符串时,对令牌#一无所知,从而报告了错误。

答案 1 :(得分:2)

#字符仅在以下C程序中允许使用:

  1. 评论
  2. 字符串和字符文字
  3. 预处理程序指令

它是用C标准定义的。

在您的程序中,可以在任何这些上下文之外找到它,因此将其标记为“杂散”,并且该程序将被拒绝。

C标准没有指定哪个翻译阶段负责诊断。无论如何,它们只是概念阶段,在真正的编译器中可能无法识别。因此,关于在预处理过程中是否发出错误的问题还没有得到很好的定义。