Start of execution
Please, tell me from where execution starts in c++, hope your answer is "from main".
Then what about this?
class abc
{
public:
abc()
{
cout<<"hello";
}
};
const abc obj;
int main( )
{
cout<<"Main";
}
output:
helloMain
Please elaborat开发者_开发问答e.
Global variables are created (and hence their constructors called) before main
is invoked.
Answer to OP's comment:
If you want to dig deeper than the code written by you, there are things happening before main
is invoked, of which I myself don't have a clear picture. I am talking about the code that we write - where the entry point is the main
function, which is invoked after initializing the global variables. As it happens, initialization of a class instance means calling its constructor.
Hence in short, the line const abc obj;
creates a global variable of type abc
which is initialized (it's default constructor with a print statement is called) before the main
is called. Hence the output helloMain
From your comments to the other answers strut, it sounds like a 10,000 foot view might assist in understanding.
The exact steps involved in launching an application differs between OSes, compilers, and programming languages but the "general" process is essentially the same.
- The OS kernel is asked to start a new process that runs the target executable
- The kernel creates a new process to host the exectuable
- The kernel sets up basic process attributes: File descriptors, environment variables, security attributes, etc.
- The kernel runs a user-mode "loader" to actually open the file contianing the executable and get it ready for execution
- The loader reads the file containing the executable and breaks it out into various segments: global variable data, executable code, etc
- The loader resolves any dynamic-link library symbols and properly lays out memory for the executable code (essentially, this step involves making sure that all pointers in the program point to the proper locations)
- The loder then invokes the "entry" function of the executable. However, this is not your 'main' function. The 'entry' function is usually hidden by the OS/compiler to allow for pre-main initialization code to run.
- In the case of C++ the entry function will most likely look something like the following:
int __entry( int argc, char *argv[] )
{
// configure standard I/O streams, threading tables, & other utilities
initialize_c_runtime();
// run the constructors for all static objects
initialize_static_cplusplus_objects();
// Now, finally, after *all* that we execute the 'main' function
return main(argc, argv);
}
You declared obj
as a const variable of class abc
. The variable obj
is assigned a default value before your program starts execution by code that is emmited by the compiler. This code calls the default constructor to create a default object of type abc
and assigns it to obj
.
Leaving static initializations aside, it's correct to say execution starts from main()
.
Since obj
is a global object, it will be instantiated before main
executes. It is just like any other global variables, i.e., when you declare an integer variable as global, it contains 0, not any garbage value. So, your object is instantiating, and calling the constructor which in turn prints the hello
string.
An application does not start from main. Following are some stack snapshots from the start of main (for a console app, unicode version) compiled with VS2005:
myapp.exe!wmain(int argc=0x00000001, wchar_t * * argv=0x00364d68) Line 67 C++
myapp.exe!__tmainCRTStartup() Line 594 + 0x17 bytes kernel32.dll!_BaseProcessStart@4() + 0x23 bytes
The first function that can be said to run in the new process context in user mode is BaseProcessStart, which is a Win32 level function. It calls the CRT-level mainCRTStartup, which uses various data sections in the binary image itself to run various initializers - e.g., global constructors such as your obj. In fact, you can set a breakpoint in your ctor and watch it yourself:
myapp.exe!`dynamic initializer for'obj''()
msvcr80.dll!_initterm(...)
myapp.exe!__tmainCRTStartup()
kernel32.dll!_BaseProcessStart@4()
(Having some formatting difficulties there). initterm is the function that iterates on global objects and calls their constructors.
The stacks would look different on different platforms and compilers (and even on VS, very different for an MFC app) but the idea is always the same: the runtime uses binary image info to initialize global objects before your own main is entered.
What happens is implied by the meaning of the code you wrote. That meaning is defined by the C++ standard.
The standard guarantees that by the time main()
starts running, all global objects are available for use, i.e. they have been constructed. Thus, if an object's construction has side effects observable from "outside" the program - like I/O - those side effect must happen before main()
gets called.
C++ guarantees more, though. All objects that are in scope must be available, i.e. constructed. No matter what the scope is. Since global variables are in scope of main()
, they must be constructed before main()
is called. But this applies to all other scopes.
You can try running the code below interactively in a debugger online and see exactly what happens.
#include <iostream>
struct Hello {
static int counter;
int this_counter = counter++;
Hello() { std::cout << "Hello " << this_counter << std::endl; }
~Hello() { std::cout << "Goodbye " << this_counter << std::endl; }
static void say_hello() {
int this_counter = counter++;
std::cout << "Hello and goodbye " << this_counter << std::endl;
}
};
int Hello::counter = 1;
const Hello hello1;
void hello4() { // scope 4
Hello hello4;
// scope 4+ - hello4 is in that scope
}
int main()
{ // entering scope 2
Hello hello2;
// scope 2+ - hello2 is in that scope
Hello::say_hello(); // hello3
hello4();
}
精彩评论