15

我对#define陈述有些困惑。在库中,它们似乎是一种跨不同文件的通信方式,有很多#ifdefs 和#ifndefs。

话虽如此,我现在有两个文件file1.cfile2.c一起编译,#define TEST 10里面有file2.c. 然而,当我在编译器TEST内部使用时file2.c,会出现以下错误消息:

'TEST' undeclared (first use in this function)

#define指令是全球性的吗?

4

4 回答 4

19

#defines 不是全局的,它们只是使用它们的地方的替换(如果在同一个编译单元中声明)

它们不是全局变量,它们不是符号,它们与链接无关,它们仅在预编译时相关。

于 2012-05-09T09:02:02.160 回答
11

#defined 宏是全局的,因为它们不遵循正常的 C 范围规则。宏的文本替换将(几乎)应用于宏名称出现在其#define. (值得注意的例外是宏名称是注释的一部分或字符串文字的一部分。)

如果您在头文件中定义宏,则该头文件的任何文件#include都将继承该宏(无论是否需要),除非该文件随后使用#undef.

在您的示例中,file2.c不了解TEST宏。#define它怎么会知道从哪里取货file1.c?用魔法?由于宏对源代码执行文本替换,因此在生成的目标文件中没有它们的表示。file2.c因此需要知道替换规则本身,如果你想在多个文件之间共享它,它#define需要存在于你的文件的公共头文件.c#include

如果您特别询问#ifdef您在库中看到的 s 有多少工作,其中许多可能会检查编译环境提供的预定义宏名称。例如,C99 编译器定义了一个__STDC_VERSION__指定语言版本的宏;Microsoft 编译器定义了一个_MSC_VER宏。(通常这些预定义的宏以前导下划线开头,因为这些名称是为编译器保留的。)

此外,大多数编译器允许将简单的宏定义为命令行参数。例如,您可以通过gcc -DNDEBUG file1.cto compile file.cwith NDEBUGdefined to disable编译您的代码assert

于 2012-05-09T09:26:22.407 回答
1

以防有人稍后阅读此内容,并添加一些实用信息:

  • 一些环境,如 atmel、vs 或 iar,允许您定义全局 #define 指令。它们基本上以某种命令行格式将这些定义的值传递给预编译器。
  • 您可以在批处理命令或 makefile 等中执行相同的操作。
  • Arduino 总是在所有编译中添加一个板变体(通常位于 hardware\arduino\variants)。此时,您可以创建一个包含全局定义指令的新板,并以这种方式使用它。例如,您可以在包含一些调试指令的原始 mega2560 之外定义一个 mega2560(调试)板。您将在“boards.txt”中添加对该变体的引用,方法是复制粘贴一些文本并正确修改它。

归根结底,您将不得不以一种或另一种方式将该全局 hfile 或全局指令提供给编译器。

于 2017-09-12T13:59:22.367 回答
0

你应该制作一个 file1.h 并将你的定义放在那里。然后在file2.c

#include "file1.h"

像馅饼一样容易:)

于 2012-05-09T09:29:13.370 回答