I wrote the following C++ program
class MyClass {
public:
int i;
int j;
MyClass() {};
};
int main(void)
{
MyClass inst;
inst.i = 1;
inst.j = 2;
}
and I compiled.
# g++ program.cpp
# ls -l a.out
-rwxr-xr-x 1 root wheel 4837 Aug 7 20:50 a.out
Then, I #include
d the header file iostream in the source file and I compiled again.
# g++ program.cpp
# ls -l a.out
-rwxr-xr-x 1 root wheel 6505 Aug 7 20:54 a.out
The file size, as expected, was increased.
I also wrote the following C program
int main(void)
{
int i = 1;
int j = 2;
}
and I compiled
# gcc program.c
# ls -l a.out
-rwxr-xr-x 1 root wheel 4570 Aug 7 21:01 a.out
Then, I #include
d the header file stdio.h and I compiled again
# gcc program.c
# ls -l a.out
-rwxr-xr-x 1 root wheel 4570 Aug 7 21:04 a.out
Oddly enough, the executable files' size remained the same.
By including iostream
in your source file, the compiler needs to generate code to setup and tear down the C++ standard I/O library. You can see this by looking at the output from nm
, which shows the symbols (generally functions) on your object file:
$ 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) ...
(--demangle
takes the C++ function names "mangled" by by the compiler and produces more meaningful names. The first column is the address, if the function is included in the executable. The second column is the type. "t" is code in the "text" segment. "U" are symbols linked in from other places; in this case, from the C++ shared library.)
Compare this with the functions generated from your source file without including 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) ...
When your source file included iostream
, the compiler generated several functions not present without iostream
.
When your source file includes only stdio.h
, the generated binary is similar to the test without iostream
, since the C standard I/O library doesn't need any extra initialization above and beyond what's already happening in the C dynamic library. You can see this by looking at the nm
output, which is identical.
In general, though, trying to intuit information about the amount of code generated by a particular source file based on the size of the executable is not going to be meaningful; there's too much that could change, and simple things like the location of the source file may change the binary if the compiler includes debugging information.
You may also find objdump
useful for poking around at the contents of your executables.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With