首页 > 解决方案 > C 预处理输出包含包含文件的重新定义

问题描述

我对进一步修改 C 预处理代码有一个坏(好?)的想法(称之为思想实验。)

为了实现这一目标,我得到了以下 shell 命令序列。请注意,我没有对预处理代码添加任何修改,但保留了这样做的能力:

#!/bin/bash
gcc -E debug/*.h debug/*.c src/* > build/main.i
#Command to modify build/main.i in future
gcc -Wpointer-arith -Wall ./build/main.i -o ./bin/main.exe 

但是,在运行最后一条命令编译代码时,会产生一堆重定义错误。下面是一个例子。甚至 C 标准函数也在做同样的事情。

In file included from src/String.c:3:
src/String.h:32:3: error: conflicting types for 'String'
   32 | } String;
      |   ^~~~~~
In file included from debug/StringDebug.c:5:
debug/../src/String.h:32:3: note: previous declaration of 'String' was here
   32 | } String;
      |   ^~~~~~
...many many more...
<path>\mingw\include\stdlib.h:916:61: error: redefinition of 'setenv'
  916 | __cdecl __MINGW_NOTHROW  int setenv( const char *__n, const char *__v, int __f )
      |                                                             ^~~~~~
In file included from debug/../src/Object.h:4,
                 from debug/BasicTypeDebug.c:2:
<path>\mingw\include\stdlib.h:916:61: note: previous definition of 'setenv' was here
  916 | __cdecl __MINGW_NOTHROW  int setenv( const char *__n, const char *__v, int __f )
      |                                                             ^~~~~~

查看 build/main.i 确认同一个文件被多次包含。我有标头保护并且不在我的头文件中声明任何变量。我知道没有任何问题,因为运行正常的编译命令(如下)可以工作。

gcc -Wpointer-arith -Wall -o ./bin/main.exe debug/*.h debug/*.c src/*

看看这个问题,我对发生的事情的猜测是,预处理器在被自身调用时,会将每个翻译单元的输出放入一个文件中,从而创建重复项。但是,因为正常的编译命令有效,所以我的猜测是,在调用编译器时,每个翻译单元都会调用一次预处理器,而不仅仅是预处理器本身。

所以我的问题是双重的:

  1. 我的猜测是否正确,或者如果它不正确,实际发生了什么?
  2. 如果我的猜测是正确的,你如何告诉 gcc 每个翻译单元输出一个预处理文件?

我明白我正在尝试做的不一定是“正确的”,更多的是看看什么可以做,什么不能做。

编辑

在下面的评论中查看 kaylum 的答案以获得答案。不知道我是如何错过回顾的,但事后看来是 20/20。

标签: ccompilationpreprocessor

解决方案


推荐阅读