On May 25, 6:42 pm, "JohnQ" <johnqREMOVETHISprogram...@yahoo.com> wrote:
> The way I understand the startup of a C++ program is:
> A.) The stuff that happens before the entry point. > B.) The stuff that happens between the entry point and the calling of > main(). > C.) main().
> So, if the above is OK, does static initialization occur during A or B? What > happens during A?
> John
main() is the entry point. The answer depends on whether the static variable is local or not (in which case Construct on First Use applies). Is the static variable a member of a class? Was it defined? Is it a global (in a compilation unit)?
You might gain some insight with the FAQ: [10.11] Why are classes with static data members getting linker errors? [10.12] What's the "static initialization order fiasco"? [10.13] How do I prevent the "static initialization order fiasco"? [10.15] How do I prevent the "static initialization order fiasco" for my static data members?
> On May 25, 6:42 pm, "JohnQ" <johnqREMOVETHISprogram...@yahoo.com> > wrote: >> The way I understand the startup of a C++ program is:
>> A.) The stuff that happens before the entry point. >> B.) The stuff that happens between the entry point and the calling of >> main(). >> C.) main().
>> So, if the above is OK, does static initialization occur during A or B? >> What >> happens during A?
>> John
> main() is the entry point. > The answer depends on whether the static variable is local or not (in > which case Construct on First Use applies). Is the static variable a > member of a class? Was it defined? Is it a global (in a compilation > unit)?
I was asking in general, not for a specific piece of code. I'm calling the entry point that which my compiler calls the entry point. It is key because it it the first place in time where I can get control of the program. But if I do commandiere that point, I need to be prepared to take over the duties of that phase of startup.
>> The way I understand the startup of a C++ program is:
>> A.) The stuff that happens before the entry point. >> B.) The stuff that happens between the entry point and the calling of >> main(). >> C.) main().
>> So, if the above is OK, does static initialization occur during A or >> B? What happens during A?
>> John
> I thought main was the entry point. Anything else would be platform- > specific. So from the Standard point of view, I thought:
> 1) The stuff that happens before main > 2) The stuff that happens in main
> Global objects are initialized in 1.
I wonder what the standard says about that (for implementors). Does it really just recognize 2 phases or are there more? It seems to me that initialization of the standard libraries needs to happen before initialization of globals because the globals may need the library facilities.
A.) Phase A stuff (as delineated from subsequent phases via the vendor-supplied entry point override). B1.) Std library initialization. B2.) Global object initialization. B3.) Other stuff in phase B. C.) main().
> The way I understand the startup of a C++ program is:
> A.) The stuff that happens before the entry point. > B.) The stuff that happens between the entry point and the calling of > main(). > C.) main().
First, about terminology. "Entry point" in general means the address where execution of the program's own machine code starts. "Entry point" in the context of a particular language often means the language's designated startup function (if there is one), such as C++ "main", which is not the machine code level entry point.
You're using the general, not language-specific, meaning.
> So, if the above is OK, does static initialization occur during A or B?
Generally in B. The standard allows delayed initialization in C, but then before the first call of a function in the translation unit. The wording of this is not perfect and it's probably the only place in the standard where there is any kind of support for dynamic libraries (not all agree that it is in support of dynamic libraries).
> What happens during A?
That's system specific and generally only of interest if you're going to write a runtime library replacement using risky techniques instead of the better documented ways. Anyway, it has nothing to do with C++.
-- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail?
> I wonder what the standard says about that (for implementors). Does it > really just recognize 2 phases or are there more? It seems to me that > initialization of the standard libraries needs to happen before > initialization of globals because the globals may need the library > facilities.
> A.) Phase A stuff (as delineated from subsequent phases via the > vendor-supplied entry point override). > B1.) Std library initialization. > B2.) Global object initialization. > B3.) Other stuff in phase B. > C.) main().
Nope. There are two phases of initialization: static and dynamic. Zero-initialization and constant initialization are static initializations. Anything else is dynamic. Static initialization occurs before entry into main and before dynamic initialization. Dynamic initialization is allowed to be postponed until the first use of any function or object defined in the same translation unit.
When you get down into the mechanics, static initialization means stuffing values known at compile time into memory locations. That information can be stored directly in the executable file, and the loader can handle it. Dynamic execution requires some sort of computation at runtime. The program's startup code does it. (The compiler is allowed to convert dynamic initializations into static ones if that doesn't change the value or any values that depend on that value)
The standard library can, and often does, have implementation-specific hooks to ensure that critical parts are initialized before their use in dynamic initialization, but that's not part of the standard (except for the nifty counter trick for iostreams), nor should it be.
>> I wonder what the standard says about that (for implementors). Does it >> really just recognize 2 phases or are there more? It seems to me that >> initialization of the standard libraries needs to happen before >> initialization of globals because the globals may need the library >> facilities.
>> A.) Phase A stuff (as delineated from subsequent phases via the >> vendor-supplied entry point override). >> B1.) Std library initialization. >> B2.) Global object initialization. >> B3.) Other stuff in phase B. >> C.) main().
> Nope. There are two phases of initialization: static and dynamic. > Zero-initialization and constant initialization are static > initializations. Anything else is dynamic. Static initialization occurs > before entry into main and before dynamic initialization.
"Before dynamic initialization" yes, but where do you find the requirement of "before entry into main"?
-- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail?
Alf P. Steinbach wrote: > * Pete Becker: >> JohnQ wrote:
>>> I wonder what the standard says about that (for implementors). Does >>> it really just recognize 2 phases or are there more? It seems to me >>> that initialization of the standard libraries needs to happen before >>> initialization of globals because the globals may need the library >>> facilities.
>>> A.) Phase A stuff (as delineated from subsequent phases via the >>> vendor-supplied entry point override). >>> B1.) Std library initialization. >>> B2.) Global object initialization. >>> B3.) Other stuff in phase B. >>> C.) main().
>> Nope. There are two phases of initialization: static and dynamic. >> Zero-initialization and constant initialization are static >> initializations. Anything else is dynamic. Static initialization >> occurs before entry into main and before dynamic initialization.
> "Before dynamic initialization" yes, but where do you find the > requirement of "before entry into main"?
> Alf P. Steinbach wrote: > > * Pete Becker: > >> JohnQ wrote:
> >>> I wonder what the standard says about that (for implementors). Does > >>> it really just recognize 2 phases or are there more? It seems to me > >>> that initialization of the standard libraries needs to happen before > >>> initialization of globals because the globals may need the library > >>> facilities.
> >>> A.) Phase A stuff (as delineated from subsequent phases via the > >>> vendor-supplied entry point override). > >>> B1.) Std library initialization. > >>> B2.) Global object initialization. > >>> B3.) Other stuff in phase B. > >>> C.) main().
> >> Nope. There are two phases of initialization: static and dynamic. > >> Zero-initialization and constant initialization are static > >> initializations. Anything else is dynamic. Static initialization > >> occurs before entry into main and before dynamic initialization.
> > "Before dynamic initialization" yes, but where do you find the > > requirement of "before entry into main"?
> You're right, not required.
Exactly. This allows the implementation to have a "hidden statement" to be the first thing to be executed in main, where this staetement performs all global initialisations. This is the reason (so far as I understood it) that main is not reentrant (an application is not allowed to call main).
> Exactly. This allows the implementation to have a "hidden statement" > to be the first thing to be executed in main, where this staetement > performs all global initialisations. This is the reason (so far as I > understood it) that main is not reentrant (an application is not > allowed to call main).
That's certainly the case for dynamic initialization, in large part because that's how cfront did it. There's less need for this to apply to static initialziations, which C has always handled. But there's no good reason to ban it, either.
>* JohnQ: >> The way I understand the startup of a C++ program is:
>> A.) The stuff that happens before the entry point. >> B.) The stuff that happens between the entry point and the calling of >> main(). >> C.) main().
> First, about terminology. "Entry point" in general means the address > where execution of the program's own machine code starts. "Entry point" > in the context of a particular language often means the language's > designated startup function (if there is one), such as C++ "main", which > is not the machine code level entry point.
> You're using the general, not language-specific, meaning.
OK. It would seem to me though that initialization of objects I create are of the program. Hence, the "entry point" at somewhere just before that intialization takes place seems more appropriately called "entry point" than main. "main" seems like "program beginning execution point".
>> So, if the above is OK, does static initialization occur during A or B?
> Generally in B. The standard allows delayed initialization in C, but then > before the first call of a function in the translation unit. The wording > of this is not perfect and it's probably the only place in the standard > where there is any kind of support for dynamic libraries (not all agree > that it is in support of dynamic libraries).
OK.
>> What happens during A?
> That's system specific and generally only of interest if you're going to > write a runtime library replacement using risky techniques instead of the > better documented ways.
Can you explain "risky techniques vs. better documented ways"?
>Anyway, it has nothing to do with C++.
Writing a replacement runtime library has nothing to do with C++??
>> I wonder what the standard says about that (for implementors). Does it >> really just recognize 2 phases or are there more? It seems to me that >> initialization of the standard libraries needs to happen before >> initialization of globals because the globals may need the library >> facilities.
>> A.) Phase A stuff (as delineated from subsequent phases via the >> vendor-supplied entry point override). >> B1.) Std library initialization. >> B2.) Global object initialization. >> B3.) Other stuff in phase B. >> C.) main().
> Nope. There are two phases of initialization: static and dynamic. > Zero-initialization and constant initialization are static > initializations. Anything else is dynamic. Static initialization occurs > before entry into main and before dynamic initialization. Dynamic > initialization is allowed to be postponed until the first use of any > function or object defined in the same translation unit.
> When you get down into the mechanics, static initialization means stuffing > values known at compile time into memory locations. That information can > be stored directly in the executable file, and the loader can handle it. > Dynamic execution requires some sort of computation at runtime. The > program's startup code does it. (The compiler is allowed to convert > dynamic initializations into static ones if that doesn't change the value > or any values that depend on that value)
> The standard library can, and often does, have implementation-specific > hooks to ensure that critical parts are initialized before their use in > dynamic initialization, but that's not part of the standard (except for > the nifty counter trick for iostreams), nor should it be.
OK, good explanation. I guess having the "entry point" given by VC++ is a luxury value-add (one I like by the way).
> "Alf P. Steinbach" <al...@start.no> wrote in message > news:5bq7r6F2t8e2fU1@mid.individual.net... >> * JohnQ: >>> The way I understand the startup of a C++ program is:
>>> A.) The stuff that happens before the entry point. >>> B.) The stuff that happens between the entry point and the calling of >>> main(). >>> C.) main().
[snip]
>>> What happens during A? >> That's system specific and generally only of interest if you're going to >> write a runtime library replacement using risky techniques instead of the >> better documented ways.
> Can you explain "risky techniques vs. better documented ways"?
As an example, in Windows you can (or could), undocumented, just return from the machine code entry point, as if it were a function called by the OS. The documented way is to call ExitProcess.
>> Anyway, it has nothing to do with C++.
> Writing a replacement runtime library has nothing to do with C++??
No, not with the C++ language as defined by the Holy Standard, which is what we discuss here. Of course it has a lot to do with in-practice C++. But, it's generally very environment-specific, and so, off-topic.
-- A: Because it messes up the order in which people normally read text. Q: Why is it such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail?
On May 26, 12:42 am, "JohnQ" <johnqREMOVETHISprogram...@yahoo.com> wrote:
> The way I understand the startup of a C++ program is:
> A.) The stuff that happens before the entry point. > B.) The stuff that happens between the entry point and the calling of > main(). > C.) main().
> So, if the above is OK, does static initialization occur during A or B? What > happens during A?
> John
During A nothing happens, theres no A.
Imagine main or WinMain on windows being the normal function called by RealEntryPoint - first function called on executing your program, in effect it calls your main or WinMain function. Between call to RealEntryPoint and main function, class static, file static, function static, global variables are constructed. By standard in random order, but in effect being order of the object files are linked into the main executable.
Should anything stay unclear on this one, I can provide the example or explain in more detail.
pawel.ku...@gmail.com wrote: > On May 26, 12:42 am, "JohnQ" <johnqREMOVETHISprogram...@yahoo.com> > wrote: >> The way I understand the startup of a C++ program is:
>> A.) The stuff that happens before the entry point. >> B.) The stuff that happens between the entry point and the calling of >> main(). >> C.) main().
>> So, if the above is OK, does static initialization occur during A or B? What >> happens during A?
>> John
> During A nothing happens, theres no A.
On the contrary: that's often when static initialiaton occurs, before any code in the executable starts running. The program loader does that.
> Imagine main or WinMain on windows being the normal function called by > RealEntryPoint - first function called on executing your program, > in effect it calls your main or WinMain function. > Between call to RealEntryPoint and main function, class static, file > static, function static, global variables are constructed. > By standard in random order, but in effect being order of the object > files are linked into the main executable.
The standard doesn't require random order. It says that the order is unspecified.
> On May 26, 12:42 am, "JohnQ" <johnqREMOVETHISprogram...@yahoo.com> > wrote: > > The way I understand the startup of a C++ program is: > > A.) The stuff that happens before the entry point. > > B.) The stuff that happens between the entry point and the calling of > > main(). > > C.) main(). > > So, if the above is OK, does static initialization occur > > during A or B? What happens during A? > During A nothing happens, theres no A.
On my systems (Solaris, Linux and Windows), the program is loaded from disk before starting execution at the entry point. And static initialization takes place during the load from disk.
Of course, all this isn't very relevant to the C++ programmer. Static initialization takes place some time before the first line of code gets executed, or at least before it is possible to access the variable in any way. So whether the system does it when loading the program, or arranges for the first access to trap, and does it then, there's no way to tell in your program.
> Imagine main or WinMain on windows being the normal function called by > RealEntryPoint - first function called on executing your program, > in effect it calls your main or WinMain function. > Between call to RealEntryPoint and main function, class static, file > static, function static, global variables are constructed.
Maybe. In practice, this will happen before the first line of your code in main, but technically, the standard allows a later initialization.
> By standard in random order, but in effect being order of the object > files are linked into the main executable.
An unspecified order. Except that the order is specified within a single source file; it's only the order of the source files are treated in which is unspecified. And historically, at least (i.e. with CFront), the order was in fact the opposite the order of inclusion by the linker. (As far as I know, this was never documented nor guaranteed. But it did cover up a certain number of errors, since statics in low level libraries tended to be constructed before any statics in the code which used them.) A quick check shows that g++ still respects this order.
-- James Kanze (GABI Software) email:james.ka...@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> On May 26, 12:42 am, "JohnQ" <johnqREMOVETHISprogram...@yahoo.com> > wrote: >> The way I understand the startup of a C++ program is:
>> A.) The stuff that happens before the entry point. >> B.) The stuff that happens between the entry point and the calling of >> main(). >> C.) main().
>> So, if the above is OK, does static initialization occur during A or B? >> What >> happens during A?
>> John
> During A nothing happens, theres no A.
From the other posts, they say that program load and static initialization (probably) occur during A. So, we have:
A.) Program load and (probably) static initialization. B.) Dynamic initialization, runtime library initialization, registering of global destructors (?). C.) main().
> <pawel.ku...@gmail.com> wrote in message > news:1180300698.839073.235860@q69g2000hsb.googlegroups.com... > > On May 26, 12:42 am, "JohnQ" <johnqREMOVETHISprogram...@yahoo.com> > > wrote: > >> The way I understand the startup of a C++ program is: > >> A.) The stuff that happens before the entry point. > >> B.) The stuff that happens between the entry point and the calling of > >> main(). > >> C.) main(). > >> So, if the above is OK, does static initialization occur > >> during A or B? What happens during A? > > During A nothing happens, theres no A. > From the other posts, they say that program load and static > initialization (probably) occur during A. So, we have: > A.) Program load and (probably) static initialization. > B.) Dynamic initialization, runtime library initialization, registering of > global destructors (?). > C.) main().
Sort of. The runtime library generally uses the same initialization mechanisms as the rest, and does nothing special. (This isn't quite true, and some elements from C, such as stdin, probably do require special handling.) And there's normally no need to "register" destructors; exit uses the same means of finding them that the initialization did.
-- James Kanze (GABI Software) email:james.ka...@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> <pawel.ku...@gmail.com> wrote in message > news:1180300698.839073.235860@q69g2000hsb.googlegroups.com... > > On May 26, 12:42 am, "JohnQ" <johnqREMOVETHISprogram...@yahoo.com> > > wrote: > >> The way I understand the startup of a C++ program is: > >> A.) The stuff that happens before the entry point. > >> B.) The stuff that happens between the entry point and the calling of > >> main(). > >> C.) main(). > >> So, if the above is OK, does static initialization occur > >> during A or B? What happens during A? > > During A nothing happens, theres no A. > From the other posts, they say that program load and static > initialization (probably) occur during A. So, we have: > A.) Program load and (probably) static initialization. > B.) Dynamic initialization, runtime library initialization, registering of > global destructors (?). > C.) main().
"Sort of. The runtime library generally uses the same initialization mechanisms as the rest, and does nothing special. (This isn't quite true, and some elements from C, such as stdin, probably do require special handling.) And there's normally no need to "register" destructors; exit uses the same means of finding them that the initialization did."
I probably got the terminology "registering destructors" wrong. I was just remembering what I "learned" from the LibCTiny documentation. Here'a a quote from that doc:
"All things considered, getting static constructors to work in LIBCTINY was relatively easy. It was mostly a matter of defining the right data segments (specifically, .CRT$XCA and .CRT$XCZ), and calling _initterm from the correct spot in the startup code. Getting static destructors to work was a bit trickier. Unlike the function pointer array that the compiler and linker conspire to create for static constructors, the list of static destructors to call is built at runtime. To build this list, the compiler generates calls to the atexit function, which is part of the Visual C++ runtime. The atexit function takes a function pointer and adds the pointer to a first-in, last-out list. When the EXE or DLL unloads, the runtime library iterates through the list and calls each function pointer."
(LibTinyC is described in an early Dr. Dobbs article and an updated article (and code) on the web. The article is "Reduce EXE and DLL Size with LIBCTINY.LIB" by Matt Peitrek).
I'm not sure I'd use it in production code (because I don't have the required low level knowledge to be confident about it or confidence that I'd be able to fix it if it "breaks" unexpectedly) but it sure was fun to play with one day (hehe, actually, I'm still building small test code under that "environment").
Personally, I don't think it would be out of line to suggest that the "entry point" be accepted as being under the control of the programmer instead of just everything after main. That would increase mechanism and decrease policy in the standard a little. (Now my question is "what is the difference between a hosted and non-holsted C++ implementation?". Somehow, I think it's related?).