Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a program with a global variable called main instead of a main function work?

Consider following program:

#include <iostream> int main = ( std::cout << "C++ is excellent!\n", 195 );  

Using g++ 4.8.1 (mingw64) on Windows 7 OS, the program compiles and runs fine, printing:

C++ is excellent!

to the console. main appears to be a global variable rather than a function; how can this program execute without the function main()? Does this code conform to the C++ standard? Is the behavior of the program is well defined? I have also used the -pedantic-errors option but the program still compiles and runs.

like image 454
Destructor Avatar asked Sep 29 '15 18:09

Destructor


People also ask

Can you declare a global variable in main?

Yes. Like I said, pass the array with parameters. This has nothing to do with size of the project really, globals get you into trouble very quickly.

What happens when the global variable name and the function name are same?

It is usually not a good programming practice to give different variables the same names. If a global and a local variable with the same name are in scope, which means accessible, at the same time, your code can access only the local variable.

What is the main problem with using global variables?

Using global variables causes very tight coupling of code. Using global variables causes namespace pollution. This may lead to unnecessarily reassigning a global value. Testing in programs using global variables can be a huge pain as it is difficult to decouple them when testing.

Where can a global variable be called from in a program?

A global variable is a programming language construct, a variable type that is declared outside any function and is accessible to all functions throughout the program.


1 Answers

Before going into the meat of the question about what is going on, it is important to point out that program is ill-formed as per defect report 1886: Language linkage for main():

[...] A program that declares a variable main at global scope or that declares the name main with C language linkage (in any namespace) is ill-formed. [...]

The most recent versions of clang and gcc makes this an error and the program will not compile (see gcc live example):

error: cannot declare '::main' to be a global variable int main = ( std::cout << "C++ is excellent!\n", 195 );      ^ 

So why was there no diagnostic in older versions of gcc and clang? This defect report did not even have a proposed resolution until late 2014 and so this case was only very recently explicitly ill-formed, which requires a diagnostic.

Prior to this, it seems like this would be undefined behavior since we are violating a shall requirement of the draft C++ standard from section 3.6.1 [basic.start.main]:

A program shall contain a global function called main, which is the designated start of the program. [...]

Undefined behavior is unpredictable and does not require a diagnostic. The inconsistency we see with reproducing the behavior is typical undefined behavior.

So what is the code actually doing and why in some cases does it produce results? Let's see what we have:

declarator   |        initializer---------------------------------- |        |                                           | v        v                                           v int main = ( std::cout << "C++ is excellent!\n", 195 );      ^      ^                                   ^     |      |                                   |     |      |                                   comma operator     |      primary expression global variable of type int 

We have main which is an int declared in the global namespace and is being initialized, the variable has static storage duration. It is implementation defined whether the initialization will take place before an attempt to call main is made but it appears gcc does do this before calling main.

The code uses the comma operator, the left operand is a discarded value expression and is used here solely for the side effect of calling std::cout. The result of the comma operator is the right operand which in this case is the prvalue 195 which is assigned to the variable main.

We can see sergej points out the generated assembly shows that cout is called during static initialization. Although the more interesting point for discussion see live godbolt session would be this:

main: .zero   4 

and the subsequent:

movl    $195, main(%rip) 

The likely scenario is that the program jumps to the symbol main expecting valid code to be there and in some cases will seg-fault. So if that is the case we would expect storing valid machine code in the variable main could lead to workable program, assuming we are located in a segment that allows code execution. We can see this 1984 IOCCC entry does just that.

It appears we can get gcc to do this in C using (see it live):

const int main = 195 ; 

It seg-faults if the variable main is not const presumably because it is not located in an executable location, Hat Tip to this comment here which gave me this idea.

Also see FUZxxl answer here to a C specific version of this question.

like image 110
Shafik Yaghmour Avatar answered Oct 11 '22 21:10

Shafik Yaghmour