【问题标题】:Macro expands correctly, but gives me "expected expression" error宏正确扩展,但给了我“预期的表达式”错误
【发布时间】:2014-07-24 00:18:58
【问题描述】:

我对我的问题做了一个简单的简化:

#define STR_BEG "
#define STR_END "

int main()
{
    char * s = STR_BEG abc STR_END;

    printf("%s\n", s);
}

编译时出现以下错误:

static2.c:12:16: error: expected expression
    char * s = STR_BEG abc STR_END;
               ^
static2.c:7:17: note: expanded from macro 'STR_BEG'
#define STR_BEG "

现在,如果我运行预处理器gcc -E myfile.c,我会得到:

int main()
{
    char * s = " abc ";


    printf("%s\n", s);
}

这正是我想要的,并且是完全合法的结果代码。那么有什么关系呢?

【问题讨论】:

  • 预处理器根据预处理器标记工作,而不是任意字符。
  • 如果是这样,那为什么我在运行预处理器(-E)时没有报错,只有在我尝试编译时才报错?
  • 我应该更清楚一点:预处理阶段的输出是一个标记序列,而不是一个字符序列。您的输出标记序列不是有效的 C 程序。您没有一个“字符串文字”标记,而是三个无效标记(或者更确切地说是两个无效标记和一个随机标识符)。

标签: c macros c-preprocessor


【解决方案1】:

宏并没有真正“正确”扩展,因为它不是一个有效的 C 预处理程序。正如Kerrek 所说,预处理器完全对任意字符序列起作用-它对整个标记起作用。标记是与构成有效 C 代码的形式(或多或少)相同的标点符号、标识符、数字、字符串等。这些定义没有描述有效的字符串——它们打开它们,并且未能在行尾之前关闭它们。所以一个无效的令牌序列被传递给预处理器。它设法从无效程序产生输出的事实可以说是很方便的,但它并不能使它正确,而且它几乎可以肯定地最多保证来自预处理器的垃圾输出。您需要终止您的字符串以使它们形成整个令牌 - 现在它们形成垃圾输入。

要实际将标记或标记序列用引号括起来,请使用字符串化运算符#

#define STRFY(A) #A
STRFY(abc) // -> "abc"

如果您在启用-Wall 标志的情况下编译预处理,GCC 和类似的编译器会警告您此类错误。

(我假设您仅在尝试编译为 C 时出现错误,但在两次执行时不会出现错误,因为在编译器内部,它保留了这些是“损坏”标记的信息,如果你写出一个中间文件,然后在第二遍编译预处理的源代码......如果是这样,这是一个实现细节,不要依赖它。)


您的实际问题的一种可能的解决方案可能如下所示:

#define LPR (
#define start STRFY LPR
#define end )
#define STRFY(A) #A
#define ID(...) __VA_ARGS__

ID(
  char * s = start()()()end;  // -> char * s = "()()()";
)

不过,ID 包装器是必需的。没有它就没有办法(它可以绕过任意数量的行,甚至你的整个程序,但它必须存在,其原因在其他问题中有充分说明)。

【讨论】:

  • 我问Kerek,那为什么预处理器不报告任何错误呢?如果它真的是一个预处理器问题,我希望在预处理阶段出现错误,而不是在编译后期出现错误。它似乎成功进行了预处理,然后在尝试解析生成的代码时窒息。顺便说一句,#x 并没有真正帮助我,因为这是对相关代码的非常简单的简化。如果你想知道,我想把 start()()()end 变成“()()()”。因此,我永远无法将这些括号传递给宏。 (这是一个语言游戏的东西,不要问我这样做的最终实际目的)
  • 您可以使用# 修改任何有效令牌序列 - 将()()() 传递给它(而不是将startend 扩展为引号,将它们扩展为STRFY() 作为嵌套扩展)。你的预处理器应该报告原始代码的错误——我的——因为这是无效的CPP以及C。我猜你有一个更宽松的。尝试调高警告级别?
  • @user3870686 您的问题特定于引号(因为字符串文字的识别发生在预处理器令牌替换之前)。如果“真正的问题”不涉及引号,那么这个问题没有帮助。
  • 我确实需要它看起来像 start()()()end。同样,这是针对语言挑战的事情,我知道这是一个荒谬的要求。谢谢你的信息
猜你喜欢
  • 2021-06-23
  • 1970-01-01
  • 1970-01-01
  • 2021-05-23
  • 1970-01-01
  • 2015-11-18
  • 1970-01-01
  • 2011-12-25
  • 1970-01-01
相关资源
最近更新 更多