为什么使用D选项编译头文件会产生比使用C包装器编译头文件大得多的文件?
我有一个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倍大。这两个命令行不是应该产生相同的结果吗?一般来说,使用不同符号进行编译会
#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中),这两个文件产生的文件名完全相同。更清楚?