为什么C头文件不会增加二进制文件的大小?

Pet*_*osB 11 c++ executable header-files

我写了以下C++程序

class MyClass {
public:
        int i;
        int j;
        MyClass() {};
};

int main(void)
{
        MyClass inst;
        inst.i = 1;
        inst.j = 2;
}
Run Code Online (Sandbox Code Playgroud)

我编译了.

# g++ program.cpp
# ls -l a.out
-rwxr-xr-x  1 root  wheel  4837 Aug  7 20:50 a.out
Run Code Online (Sandbox Code Playgroud)

然后,我#include在源文件中的头文件iostream,我再次编译.

# g++ program.cpp
# ls -l a.out
-rwxr-xr-x  1 root  wheel  6505 Aug  7 20:54 a.out
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,文件大小增加了.

我还写了以下C程序

int main(void)
{
    int i = 1;
    int j = 2;
}
Run Code Online (Sandbox Code Playgroud)

我编译了

# gcc program.c
# ls -l a.out
-rwxr-xr-x  1 root  wheel  4570 Aug  7 21:01 a.out
Run Code Online (Sandbox Code Playgroud)

然后,我#include把头文件stdio.h和我再次编译

# gcc program.c
# ls -l a.out
-rwxr-xr-x  1 root  wheel  4570 Aug  7 21:04 a.out
Run Code Online (Sandbox Code Playgroud)

奇怪的是,可执行文件的大小保持不变.

Com*_*ger 18

通过iostream在源文件中包含,编译器需要生成代码来设置和拆除C++标准I/O库.您可以通过查看输出来看到这一点,该输出nm显示目标文件上的符号(通常是函数):

$ nm --demangle test_with_iostream
08049914 d _DYNAMIC
08049a00 d _GLOBAL_OFFSET_TABLE_
08048718 t global constructors keyed to main
0804883c R _IO_stdin_used
         w _Jv_RegisterClasses
080486d8 t __static_initialization_and_destruction_0(int, int)
08048748 W MyClass::MyClass()
         U std::string::size() const@@GLIBCXX_3.4
         U std::string::operator[](unsigned int) const@@GLIBCXX_3.4
         U std::ios_base::Init::Init()@@GLIBCXX_3.4
         U std::ios_base::Init::~Init()@@GLIBCXX_3.4
080485cc t std::__verify_grouping(char const*, unsigned int, std::string const&)
0804874e W unsigned int const& std::min<unsigned int>(unsigned int const&, unsigned int const&)
08049a3c b std::__ioinit
08049904 d __CTOR_END__
... (remaining output snipped) ...
Run Code Online (Sandbox Code Playgroud)

(--demangle由编译器将C++函数名称"修改"并生成更有意义的名称.第一列是地址,如果函数包含在可执行文件中.第二列是类型."t"是" text"segment."U"是从其他地方链接的符号;在这种情况下,来自C++共享库.)

将其与源文件生成的函数进行比较,不包括iostream:

$ nm --demangle test_without_iostream
08049508 d _DYNAMIC
080495f4 d _GLOBAL_OFFSET_TABLE_
080484ec R _IO_stdin_used
         w _Jv_RegisterClasses
0804841c W MyClass::MyClass()
080494f8 d __CTOR_END__
... (remaining output snipped) ...
Run Code Online (Sandbox Code Playgroud)

当您的源文件包含时iostream,编译器生成了几个不存在的函数iostream.

当您的源文件仅包含时stdio.h,生成的二进制文件类似于没有的测试iostream,因为C标准I/O库不需要任何额外的初始化,超出C动态库中已经发生的内容.你可以通过查看nm相同的输出来看到这一点.

但是,一般情况下,尝试根据可执行文件的大小直观地了解特定源文件生成的代码量并不重要; 有太多可以改变的东西,如果编译器包含调试信息,那么像源文件的位置这样的简单事情可能会改变二进制文件.

您还可以找到objdump有用的方法来浏览可执行文件的内容.


Mic*_*ael 9

头文件通常只是声明,不会直接导致生成机器代码.链接器足够智能,不会从CRT中引入未使用的函数,因此只包含stdio.h而不使用其任何函数不会导致可执行文件中的代码更多.

编辑:它们可以包括内联函数,类等,其中包括代码,但这些不应导致可执行文件大小增加,直到实际使用它们.


Ben*_*n M 7

iostream包含代码.stdio.h没有.

更具体地说,iostream中的以下定义(除了列出,并且由编译器更改)在标准库中创建的引用对象,然后链接到您的代码中:

extern istream &cin;
extern ostream &cout;
extern ostream &cerr;
extern ostream &clog;
Run Code Online (Sandbox Code Playgroud)

  • `extern`定义不生成代码; 他们只是让编译器知道它们存在,因此编译器可以在它们实际使用时引用它们. (2认同)