Include of iostream leads to different binary

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
28
down vote

favorite
5












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:?







share|improve this question


















  • 1




    The C++ design philosophy of What you don't use, you don't pay for (Foundations of C++, p. 4) is a lofty goal, however there are some situations in which it is not attained. There are quite a few things that can bloat a C++ binary and yet be useless, and you've stumbled upon one of them. Do note that the language itself does not mandate them; those are failures of tools to optimize them away.
    – Matthieu M.
    Aug 30 at 9:26






  • 2




    @MatthieuM. - To be fair, this can be called a programming error. Kinda like making a a function needlessly virtual. The goal can be better expressed as "you don't pay for what you don't ask". It's the programmer that needs to know what they are asking for.
    – StoryTeller
    Aug 30 at 10:09







  • 1




    @StoryTeller: I disagree. If the optimizer removes any instance of calls to cout because it proved the branches were never taken; you still will end-up with those useless leftovers. If you had used printf instead, then it would be fully eliminated.
    – Matthieu M.
    Aug 30 at 10:51














up vote
28
down vote

favorite
5












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:?







share|improve this question


















  • 1




    The C++ design philosophy of What you don't use, you don't pay for (Foundations of C++, p. 4) is a lofty goal, however there are some situations in which it is not attained. There are quite a few things that can bloat a C++ binary and yet be useless, and you've stumbled upon one of them. Do note that the language itself does not mandate them; those are failures of tools to optimize them away.
    – Matthieu M.
    Aug 30 at 9:26






  • 2




    @MatthieuM. - To be fair, this can be called a programming error. Kinda like making a a function needlessly virtual. The goal can be better expressed as "you don't pay for what you don't ask". It's the programmer that needs to know what they are asking for.
    – StoryTeller
    Aug 30 at 10:09







  • 1




    @StoryTeller: I disagree. If the optimizer removes any instance of calls to cout because it proved the branches were never taken; you still will end-up with those useless leftovers. If you had used printf instead, then it would be fully eliminated.
    – Matthieu M.
    Aug 30 at 10:51












up vote
28
down vote

favorite
5









up vote
28
down vote

favorite
5






5





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:?







share|improve this question














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:?









share|improve this question













share|improve this question




share|improve this question








edited Sep 3 at 10:57

























asked Aug 29 at 13:59









schorsch312

1,80921027




1,80921027







  • 1




    The C++ design philosophy of What you don't use, you don't pay for (Foundations of C++, p. 4) is a lofty goal, however there are some situations in which it is not attained. There are quite a few things that can bloat a C++ binary and yet be useless, and you've stumbled upon one of them. Do note that the language itself does not mandate them; those are failures of tools to optimize them away.
    – Matthieu M.
    Aug 30 at 9:26






  • 2




    @MatthieuM. - To be fair, this can be called a programming error. Kinda like making a a function needlessly virtual. The goal can be better expressed as "you don't pay for what you don't ask". It's the programmer that needs to know what they are asking for.
    – StoryTeller
    Aug 30 at 10:09







  • 1




    @StoryTeller: I disagree. If the optimizer removes any instance of calls to cout because it proved the branches were never taken; you still will end-up with those useless leftovers. If you had used printf instead, then it would be fully eliminated.
    – Matthieu M.
    Aug 30 at 10:51












  • 1




    The C++ design philosophy of What you don't use, you don't pay for (Foundations of C++, p. 4) is a lofty goal, however there are some situations in which it is not attained. There are quite a few things that can bloat a C++ binary and yet be useless, and you've stumbled upon one of them. Do note that the language itself does not mandate them; those are failures of tools to optimize them away.
    – Matthieu M.
    Aug 30 at 9:26






  • 2




    @MatthieuM. - To be fair, this can be called a programming error. Kinda like making a a function needlessly virtual. The goal can be better expressed as "you don't pay for what you don't ask". It's the programmer that needs to know what they are asking for.
    – StoryTeller
    Aug 30 at 10:09







  • 1




    @StoryTeller: I disagree. If the optimizer removes any instance of calls to cout because it proved the branches were never taken; you still will end-up with those useless leftovers. If you had used printf instead, then it would be fully eliminated.
    – Matthieu M.
    Aug 30 at 10:51







1




1




The C++ design philosophy of What you don't use, you don't pay for (Foundations of C++, p. 4) is a lofty goal, however there are some situations in which it is not attained. There are quite a few things that can bloat a C++ binary and yet be useless, and you've stumbled upon one of them. Do note that the language itself does not mandate them; those are failures of tools to optimize them away.
– Matthieu M.
Aug 30 at 9:26




The C++ design philosophy of What you don't use, you don't pay for (Foundations of C++, p. 4) is a lofty goal, however there are some situations in which it is not attained. There are quite a few things that can bloat a C++ binary and yet be useless, and you've stumbled upon one of them. Do note that the language itself does not mandate them; those are failures of tools to optimize them away.
– Matthieu M.
Aug 30 at 9:26




2




2




@MatthieuM. - To be fair, this can be called a programming error. Kinda like making a a function needlessly virtual. The goal can be better expressed as "you don't pay for what you don't ask". It's the programmer that needs to know what they are asking for.
– StoryTeller
Aug 30 at 10:09





@MatthieuM. - To be fair, this can be called a programming error. Kinda like making a a function needlessly virtual. The goal can be better expressed as "you don't pay for what you don't ask". It's the programmer that needs to know what they are asking for.
– StoryTeller
Aug 30 at 10:09





1




1




@StoryTeller: I disagree. If the optimizer removes any instance of calls to cout because it proved the branches were never taken; you still will end-up with those useless leftovers. If you had used printf instead, then it would be fully eliminated.
– Matthieu M.
Aug 30 at 10:51




@StoryTeller: I disagree. If the optimizer removes any instance of calls to cout because it proved the branches were never taken; you still will end-up with those useless leftovers. If you had used printf instead, then it would be fully eliminated.
– Matthieu M.
Aug 30 at 10:51












2 Answers
2






active

oldest

votes

















up vote
28
down vote



accepted










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.






share|improve this answer


















  • 3




    Initialize, and (perhaps more importantly) flush them before normal termination.
    – Jerry Coffin
    Aug 29 at 14:05










  • Interestingly, no storage for __ioinit itself is allocated. At the same time I wonder why the constructor is not in marked comdat. Is this code really duplicated in every single translation unit that uses iostream? Seems really inefficient.
    – fuz
    Aug 29 at 14:13







  • 1




    @fuz _ZStL8__ioinit is the storage for __ioinit.
    – Maxim Egorushkin
    Aug 29 at 14:14






  • 1




    @fuz - C++17's inline variable definitions can.
    – StoryTeller
    Aug 29 at 14:30






  • 4




    This is why you should include <istream> and/or <ostream> instead of <iostream> in translation units that don't need to refer to cin, cout, cerr, wcin, wcout, and wcerr.
    – zwol
    Aug 30 at 1:51

















up vote
22
down vote













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.






share|improve this answer




















  • In other words, link-time optimisation may be able to elide this, right?
    – Lightness Races in Orbit
    Aug 29 at 14:23










  • @LightnessRacesinOrbit - Theoretically, and hopefully.
    – StoryTeller
    Aug 29 at 14:25






  • 4




    Even with link-time optimization, I don't think the compiler has enough information to understand that __ioinit is superfluous in a translation unit that makes no reference to any of the standard streams.
    – zwol
    Aug 30 at 1:52










Your Answer





StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52079248%2finclude-of-iostream-leads-to-different-binary%23new-answer', 'question_page');

);

Post as a guest






























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
28
down vote



accepted










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.






share|improve this answer


















  • 3




    Initialize, and (perhaps more importantly) flush them before normal termination.
    – Jerry Coffin
    Aug 29 at 14:05










  • Interestingly, no storage for __ioinit itself is allocated. At the same time I wonder why the constructor is not in marked comdat. Is this code really duplicated in every single translation unit that uses iostream? Seems really inefficient.
    – fuz
    Aug 29 at 14:13







  • 1




    @fuz _ZStL8__ioinit is the storage for __ioinit.
    – Maxim Egorushkin
    Aug 29 at 14:14






  • 1




    @fuz - C++17's inline variable definitions can.
    – StoryTeller
    Aug 29 at 14:30






  • 4




    This is why you should include <istream> and/or <ostream> instead of <iostream> in translation units that don't need to refer to cin, cout, cerr, wcin, wcout, and wcerr.
    – zwol
    Aug 30 at 1:51














up vote
28
down vote



accepted










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.






share|improve this answer


















  • 3




    Initialize, and (perhaps more importantly) flush them before normal termination.
    – Jerry Coffin
    Aug 29 at 14:05










  • Interestingly, no storage for __ioinit itself is allocated. At the same time I wonder why the constructor is not in marked comdat. Is this code really duplicated in every single translation unit that uses iostream? Seems really inefficient.
    – fuz
    Aug 29 at 14:13







  • 1




    @fuz _ZStL8__ioinit is the storage for __ioinit.
    – Maxim Egorushkin
    Aug 29 at 14:14






  • 1




    @fuz - C++17's inline variable definitions can.
    – StoryTeller
    Aug 29 at 14:30






  • 4




    This is why you should include <istream> and/or <ostream> instead of <iostream> in translation units that don't need to refer to cin, cout, cerr, wcin, wcout, and wcerr.
    – zwol
    Aug 30 at 1:51












up vote
28
down vote



accepted







up vote
28
down vote



accepted






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.






share|improve this answer














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.







share|improve this answer














share|improve this answer



share|improve this answer








edited Aug 29 at 14:21

























answered Aug 29 at 14:04









Maxim Egorushkin

79.4k1195173




79.4k1195173







  • 3




    Initialize, and (perhaps more importantly) flush them before normal termination.
    – Jerry Coffin
    Aug 29 at 14:05










  • Interestingly, no storage for __ioinit itself is allocated. At the same time I wonder why the constructor is not in marked comdat. Is this code really duplicated in every single translation unit that uses iostream? Seems really inefficient.
    – fuz
    Aug 29 at 14:13







  • 1




    @fuz _ZStL8__ioinit is the storage for __ioinit.
    – Maxim Egorushkin
    Aug 29 at 14:14






  • 1




    @fuz - C++17's inline variable definitions can.
    – StoryTeller
    Aug 29 at 14:30






  • 4




    This is why you should include <istream> and/or <ostream> instead of <iostream> in translation units that don't need to refer to cin, cout, cerr, wcin, wcout, and wcerr.
    – zwol
    Aug 30 at 1:51












  • 3




    Initialize, and (perhaps more importantly) flush them before normal termination.
    – Jerry Coffin
    Aug 29 at 14:05










  • Interestingly, no storage for __ioinit itself is allocated. At the same time I wonder why the constructor is not in marked comdat. Is this code really duplicated in every single translation unit that uses iostream? Seems really inefficient.
    – fuz
    Aug 29 at 14:13







  • 1




    @fuz _ZStL8__ioinit is the storage for __ioinit.
    – Maxim Egorushkin
    Aug 29 at 14:14






  • 1




    @fuz - C++17's inline variable definitions can.
    – StoryTeller
    Aug 29 at 14:30






  • 4




    This is why you should include <istream> and/or <ostream> instead of <iostream> in translation units that don't need to refer to cin, cout, cerr, wcin, wcout, and wcerr.
    – zwol
    Aug 30 at 1:51







3




3




Initialize, and (perhaps more importantly) flush them before normal termination.
– Jerry Coffin
Aug 29 at 14:05




Initialize, and (perhaps more importantly) flush them before normal termination.
– Jerry Coffin
Aug 29 at 14:05












Interestingly, no storage for __ioinit itself is allocated. At the same time I wonder why the constructor is not in marked comdat. Is this code really duplicated in every single translation unit that uses iostream? Seems really inefficient.
– fuz
Aug 29 at 14:13





Interestingly, no storage for __ioinit itself is allocated. At the same time I wonder why the constructor is not in marked comdat. Is this code really duplicated in every single translation unit that uses iostream? Seems really inefficient.
– fuz
Aug 29 at 14:13





1




1




@fuz _ZStL8__ioinit is the storage for __ioinit.
– Maxim Egorushkin
Aug 29 at 14:14




@fuz _ZStL8__ioinit is the storage for __ioinit.
– Maxim Egorushkin
Aug 29 at 14:14




1




1




@fuz - C++17's inline variable definitions can.
– StoryTeller
Aug 29 at 14:30




@fuz - C++17's inline variable definitions can.
– StoryTeller
Aug 29 at 14:30




4




4




This is why you should include <istream> and/or <ostream> instead of <iostream> in translation units that don't need to refer to cin, cout, cerr, wcin, wcout, and wcerr.
– zwol
Aug 30 at 1:51




This is why you should include <istream> and/or <ostream> instead of <iostream> in translation units that don't need to refer to cin, cout, cerr, wcin, wcout, and wcerr.
– zwol
Aug 30 at 1:51












up vote
22
down vote













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.






share|improve this answer




















  • In other words, link-time optimisation may be able to elide this, right?
    – Lightness Races in Orbit
    Aug 29 at 14:23










  • @LightnessRacesinOrbit - Theoretically, and hopefully.
    – StoryTeller
    Aug 29 at 14:25






  • 4




    Even with link-time optimization, I don't think the compiler has enough information to understand that __ioinit is superfluous in a translation unit that makes no reference to any of the standard streams.
    – zwol
    Aug 30 at 1:52














up vote
22
down vote













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.






share|improve this answer




















  • In other words, link-time optimisation may be able to elide this, right?
    – Lightness Races in Orbit
    Aug 29 at 14:23










  • @LightnessRacesinOrbit - Theoretically, and hopefully.
    – StoryTeller
    Aug 29 at 14:25






  • 4




    Even with link-time optimization, I don't think the compiler has enough information to understand that __ioinit is superfluous in a translation unit that makes no reference to any of the standard streams.
    – zwol
    Aug 30 at 1:52












up vote
22
down vote










up vote
22
down vote









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.






share|improve this answer












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.







share|improve this answer












share|improve this answer



share|improve this answer










answered Aug 29 at 14:03









StoryTeller

82.4k12163228




82.4k12163228











  • In other words, link-time optimisation may be able to elide this, right?
    – Lightness Races in Orbit
    Aug 29 at 14:23










  • @LightnessRacesinOrbit - Theoretically, and hopefully.
    – StoryTeller
    Aug 29 at 14:25






  • 4




    Even with link-time optimization, I don't think the compiler has enough information to understand that __ioinit is superfluous in a translation unit that makes no reference to any of the standard streams.
    – zwol
    Aug 30 at 1:52
















  • In other words, link-time optimisation may be able to elide this, right?
    – Lightness Races in Orbit
    Aug 29 at 14:23










  • @LightnessRacesinOrbit - Theoretically, and hopefully.
    – StoryTeller
    Aug 29 at 14:25






  • 4




    Even with link-time optimization, I don't think the compiler has enough information to understand that __ioinit is superfluous in a translation unit that makes no reference to any of the standard streams.
    – zwol
    Aug 30 at 1:52















In other words, link-time optimisation may be able to elide this, right?
– Lightness Races in Orbit
Aug 29 at 14:23




In other words, link-time optimisation may be able to elide this, right?
– Lightness Races in Orbit
Aug 29 at 14:23












@LightnessRacesinOrbit - Theoretically, and hopefully.
– StoryTeller
Aug 29 at 14:25




@LightnessRacesinOrbit - Theoretically, and hopefully.
– StoryTeller
Aug 29 at 14:25




4




4




Even with link-time optimization, I don't think the compiler has enough information to understand that __ioinit is superfluous in a translation unit that makes no reference to any of the standard streams.
– zwol
Aug 30 at 1:52




Even with link-time optimization, I don't think the compiler has enough information to understand that __ioinit is superfluous in a translation unit that makes no reference to any of the standard streams.
– zwol
Aug 30 at 1:52

















 

draft saved


draft discarded















































 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52079248%2finclude-of-iostream-leads-to-different-binary%23new-answer', 'question_page');

);

Post as a guest













































































Comments

Popular posts from this blog

Long meetings (6-7 hours a day): Being “babysat” by supervisor

Is the Concept of Multiple Fantasy Races Scientifically Flawed? [closed]

Confectionery