【问题标题】:Defines compilation order定义编译顺序
【发布时间】:2021-06-16 05:53:20
【问题描述】:

假设以下文件:

inner.h

#define SIZE 1

int getValue(void);

inner.c

#include "inner.h"
static int value = SIZE;

int getValue(void)
{
    return value;
}

外部.h

#include "inner.h"

#ifdef SIZE
#undef SIZE
#define SIZE 2
#endif

int getValue2(void);

外部.c

#include "outer.h"
static int value2 = SIZE;

int getValue2(void)
{
    return value2;
}

main.c

#include <stdio.h>
#include "inner.h"
#include "outer.h"

int main (void)
{
    printf("value = %i, value2 = %i, getValue(), getValue2());
}

在编译后的代码中,会

  1. value 等于 1 或 2,因为 inner 将在 outer 之前编译?
  2. value2 等于 1 还是 2?
  3. printf 将打印什么?

【问题讨论】:

  • inner.c 从不包括outer.h(直接或间接)。所以唯一相关的SIZE 定义是inner.h 中的定义。如果仍有任何疑问,那么只需告诉编译器生成预处理输出以获得准确值(-E 选项,如果使用gcc)。
  • 感谢您的回答。我已经编辑了我的问题。
  • 我猜你的例子仍然不正确。您还没有显示任何包含outer.h 的代码。这意味着文件是无关紧要的。无论如何,一般规则是文件中的最后一个定义获胜。
  • main.c 包含的内容无关紧要。将#define 视为它出现的文件中的文本替换。所以在这种情况下,替换是在inner.c 文件中完成的。而outer.c 文件将出现编译错误,因为它没有SIZE 的定义。我认为您可能不了解预处理、编译和链接。
  • 最后一个#define 始终是适用的。所以inner.c 中的1 和outer.c 中的2

标签: c compilation include


【解决方案1】:

对预处理器扩展重要的是翻译单元。翻译单元是一个 .c 文件及其包含的所有标题。每个这样的翻译单元都有自己的宏 SIZE 扩展。

在你的情况下,你有:

  • inner.c 和inner.h 构成一个翻译单元。这里SIZE 是 1。

  • outer.c、outer.h和inner.h组成一个翻译单元。

    作为第一步,outer.h 会将#include "inner.h" 替换为#define SIZE 1 等等。所以SIZE 在遇到#ifdef SIZE 时被定义,之后它将被取消定义并重新定义。经过预处理后,SIZE 在这个翻译单元中将因此被替换为 2。

    (每个包含意味着被包含文件的内容被“递归”预处理,详见标准的“翻译阶段”一章)。

  • main.c、stdio.h、inner.h 和outer.h 组成一个翻译单元。

    这里有多次包含inner.h:来自main.c 和间接来自outer.h。这就是我们在所有标头中使用包含保护的原因,尽管在这种特定情况下并不重要。

    SIZE 在这个翻译单元中也将是 2,虽然它没有在任何地方使用,所以没关系。


值等于1或2,因为inner会在outer之前编译?

1 因为SIZEgetValue() 的定义所在的翻译单元中为1。编译顺序无关紧要。

value2 等于 1 还是 2?

2 因为SIZEgetValue2() 的定义所在的翻译单元中为2。编译顺序无关紧要。

printf 会打印什么?

构建它并亲眼看看。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-09
    • 1970-01-01
    • 1970-01-01
    • 2016-12-03
    • 1970-01-01
    相关资源
    最近更新 更多