为什么使用D选项编译头文件会产生比使用C包装器编译头文件大得多的文件?

为什么使用D选项编译头文件会产生比使用C包装器编译头文件大得多的文件?,c,gcc,C,Gcc,我有一个C文件作为头文件的包装: #define SOME_CONTROL_FLAG #include "thefile.h" 如果我用这个编译: gcc -I. -c -o thefile.o thefile.c 我得到一个9KB的对象文件。但是,如果我这样做: gcc -I. -c -D SOME_CONTROL_FLAG -o thefile.o thefile.h 我得到一个3MB的对象文件!那大约是300倍大。这两个命令行不是应该产生相同的结果吗?一般来说,使用不同符号进行编译会

我有一个C文件作为头文件的包装:

#define SOME_CONTROL_FLAG
#include "thefile.h"
如果我用这个编译:

gcc -I. -c -o thefile.o thefile.c
我得到一个9KB的对象文件。但是,如果我这样做:

gcc -I. -c -D SOME_CONTROL_FLAG -o thefile.o thefile.h
我得到一个3MB的对象文件!那大约是300倍大。这两个命令行不是应该产生相同的结果吗?

一般来说,使用不同符号进行编译会产生不同的代码 考虑以下代码。如果定义了
FOOBAR
,则文件中有更多代码需要编译(在预处理器预处理后):

#ifdef FOOBAR
int foo(int bar){
返回条+返回条;
}
#恩迪夫
内栏(内栏){
返回1+baz;
}
使用FOOBAR定义的编译会更改输出的大小。没有FOOBAR,是1232,有FOOBAR,是1328。这不是一个很大的区别,但它是一个区别

$gcc-c-code.c-o-code.o
$ls-l代码.o
-rw-rw-r--1用户1232 10月29日13:19代码
$gcc-DFOOBAR-c code.c-o code.o
$ls-l代码.o
-rw-rw-r--1用户1328十月29日13:19代码o
如果有很多条件代码,这可能非常重要。例如,定义符号可能会导致包含大量特定于平台的代码,而不定义符号可能会使函数实现成为存根

编译不同类型的代码会产生不同的代码大小 注:本部分基于。我觉得应该再详细一点

另一个可能导致不同编译对象大小的方面是GCC实际编译的对象。在你的例子中

gcc -I. -c -D SOME_CONTROL_FLAG -o thefile.o thefile.h
正在编译头文件,GCC根据文件扩展名检测到它正在使用
c-header
语言进行编译。但是,编译头文件并生成
.o
文件的事实表明,您希望将其编译为C,在这种情况下,您应该使用GCC的
-x
选项。手册页上说:

 -x language
           Specify explicitly the language for the following input files (rather than letting the compiler choose a default based on the file name suffix).  This option applies to all
           following input files until the next -x option.  Possible values for language are:

                   c  c-header  cpp-output
                   c++  c++-header  c++-cpp-output
                   objective-c  objective-c-header  objective-c-cpp-output
                   objective-c++ objective-c++-header objective-c++-cpp-output
                   assembler  assembler-with-cpp
                   ada
                   f77  f77-cpp-input f95  f95-cpp-input
                   go
                   java

       -x none
           Turn off any specification of a language, so that subsequent files are handled according to their file name suffixes (as they are if -x has not been used at all).
基于这一点,以及我在第一节中使用的代码,我们可以观察到当我们将代码编译为
c
c-header
时发生的巨大大小差异:

$ gcc -c code.h -o code.o # as a header
$ ls -l code.o 
-rw-rw-r-- 1 user user 1470864 Oct 29 14:04 code.o

$ gcc -c -x c code.h -o code.o # as c code
$ ls -l code.o 
-rw-rw-r-- 1 user user 1232 Oct 29 14:04 code.o
请注意,编译(作为标题)似乎不受符号定义的影响,但:

$ gcc -c code.h -o code.o
$ ls -l code.o 
-rw-rw-r-- 1 user user 1470864 Oct 29 14:06 code.o

$ gcc -DFOOBAR -c code.h -o code.o
$ ls -l code.o 
-rw-rw-r-- 1 user user 1470864 Oct 29 14:06 code.o

因为gcc根据其扩展来决定如何处理输入,所以我很傻。真正的等效编译行是:

gcc -I. -c -D SOME_CONTROL_FLAG -x c -o thefile.o thefile.h
其中-Xc告诉gcc将.h视为.c


生成的对象文件除了一个字节外都是相同的,因为文件名包括在内(我想是在调试信息中)。

可能是您定义的符号使其包含了更多的代码。例如,
#ifdef SOME_CONTROL_FLAG/*lots code*/#endif
。我可以理解为什么会有这样的评论,但正如Urhixidur在回答中指出的,这里的问题实际上是由于GCC(相当合理地)将头文件编译为头文件,而不是将其编译为C代码。一般来说,定义一个符号确实会在流入编译器的代码流中产生很多后果。但是在这个特殊的例子中,.c文件和带-D#的.h定义了完全相同的变量,所以它应该没有区别。我不确定我是否理解你在最后的评论中所说的。如果编译
c-header
文件不需要首先运行c预处理器,则编译
c-header
时,
-D
不会产生任何影响。在编译<代码> C/<代码>文件时,C预处理器运行,所以<代码> -d <代码>确实有区别。考虑两个交替编译:<代码> GCC—I. -C-O文件。文件< C/>代码>代码>文件> C >代码>:<代码>与
gcc-I.-c-x c-D一些\u控制\u标志-o thefile.o thefile.h相比
。除了一个字节(因为源文件的名称嵌入在.o中),这两个文件产生的文件名完全相同。更清楚?