Include of iostream leads to different binary

Compiling the following code

int main() {
return 0;
}


gives the assembly

main:
xorl %eax, %eax
ret


https://gcc.godbolt.org/z/oQvRDd

If now iostream is included

#include <iostream>
int main(){
return 0;
}


this assembly is created.

main:
xorl %eax, %eax
ret
_GLOBAL__sub_I_main:
subq $8, %rsp
movl $_ZStL8__ioinit, %edi
call std::ios_base::Init::Init() [complete object constructor]
movl $__dso_handle, %edx
movl $_ZStL8__ioinit, %esi
movl $_ZNSt8ios_base4InitD1Ev, %edi
addq $8, %rsp
jmp __cxa_atexit


Full optimization is turned on (-O3).
https://gcc.godbolt.org/z/EtrEX8

Can someone explain, why including an unused header changes the binary. What is _GLOBAL__sub_I_main:?

Each translation unit that includes <iostream> contains a copy of ios_base::Init object:

static ios_base::Init __ioinit;


This object is used to initialize the standard streams (std::cout and its friends). This method is called Schwarz Counter and it ensures that the standard streams are always initialized before their first use (provided iostream header has been included).

That function _GLOBAL__sub_I_main is code the compiler generates for each translation unit that calls the constructors of global objects in that translation unit and also arranges for the corresponding destructor calls to be invoked at exit. This code is invoked by the C++ standard library start-up code before main is called.

Including the iostream header has the effect of adding the definition of a static std::ios_base::Init object. The constructor of this static object initializes the standard stream objects std::cout, std::cerr and so forth.

The reason it's done is to avoid the static initialization order fiasco. It ensures the stream objects are properly initialized across translation units.

Comments

Popular posts from this blog

Meaning of `{}` for return expression

Get current scroll position of ScrollView in React Native

flutter websocket connection issue