【问题标题】:Why stringizing operator is only accepted as a macro?为什么字符串化运算符只被接受为宏?
【发布时间】:2019-04-11 15:56:52
【问题描述】:

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

#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;
}

这个错误是由预处理器报告的吗?如果是这样,为什么?

【问题讨论】:

  • 因为它是这样定义的。在宏之外,您可以用"" 很好地包围它
  • @EugeneSh.,在这种情况下不会是字符串文字"#world" 吗?
  • @ChristianGibbons 这个错误error: stray ‘#’ in program。在第二种情况下,gcc -E ... 的输出给出了printf("hello %s \n", "world");,这意味着预处理器将STRINGIFY(world) 扩展为"world"。所以在第一种情况下,预处理器并没有扩展# 运算符,对吧?
  • 正确,预处理器没有扩展第一个,因为它没有调用预处理器宏。
  • 我的意思是你的例子中的用例不能证明允许这种表示法是合理的。我想不出任何办法。

标签: c c-preprocessor language-lawyer


【解决方案1】:

因为#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 编译器看到第一个字符串,这对他来说没问题。但是当他看到第二个字符串时,他对令牌#一无所知,因此报错。

【讨论】:

    【解决方案2】:

    # 字符只允许在 C 程序里面:

    1. 评论
    2. 字符串和字符字面量
    3. 预处理器指令

    C 标准是这样定义的。

    在您的程序中,它在任何这些上下文之外被发现,因此它被标记为“流浪”,并且该程序被拒绝。

    C 标准没有指定哪些翻译阶段负责诊断。无论如何,它们只是概念阶段,在真正的编译器中可能会或可能不会被识别。所以在预处理过程中是否发出错误的问题没有很好的定义。

    【讨论】:

      猜你喜欢
      • 2013-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-26
      • 2021-01-28
      • 1970-01-01
      相关资源
      最近更新 更多