-1

I had very simple program as below.

int main = 0;

This program as a.c file compiled fine with gcc-4.8,gcc-5,gcc-6,gcc-7 and gcc-8 and application crashed when executed.

Same program as a.cpp file compiled fine with g++-4.8 and g++-5 and application crashed when executed. But with later version of g++ it gives compile time error.

Below is my questions.

  1. Why a.cpp compile fine with g++-4.8 and 5, but not with later one? Does it bug in previous version of g++ OR some improvement in c++ standard?
  2. If it compile successfully then why application get crashed?

Below is details compiler and output of compilation/execution.

+ gcc-4.8 --version
gcc-4.8 (Ubuntu 4.8.5-4ubuntu8) 4.8.5
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ gcc-4.8 c.c
+ ./a.out
Segmentation fault      (core dumped)
+ gcc-5 --version
gcc-5 (Ubuntu 5.5.0-12ubuntu1) 5.5.0 20171010
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ gcc-5 c.c
+ ./a.out
Segmentation fault      (core dumped)
+ gcc-6 --version
gcc-6 (Ubuntu 6.5.0-2ubuntu1~18.04) 6.5.0 20181026
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ gcc-6 c.c
+ ./a.out
Segmentation fault      (core dumped)
+ gcc-7 --version
gcc-7 (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ gcc-7 c.c
+ ./a.out
Segmentation fault      (core dumped)
+ gcc-8 --version
gcc-8 (Ubuntu 8.3.0-6ubuntu1~18.04.1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ gcc-8 c.c
+ ./a.out
Segmentation fault      (core dumped)
+ g++-4.8 --version
g++-4.8 (Ubuntu 4.8.5-4ubuntu8) 4.8.5
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ g++-4.8 c.cpp
+ ./a.out
Segmentation fault      (core dumped)
+ g++-5 --version
g++-5 (Ubuntu 5.5.0-12ubuntu1) 5.5.0 20171010
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ g++-5 c.cpp
+ ./a.out
Segmentation fault      (core dumped)
+ g++-6 --version
g++-6 (Ubuntu 6.5.0-2ubuntu1~18.04) 6.5.0 20181026
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ g++-6 c.cpp
c.cpp:1:5: error: cannot declare ‘::main’ to be a global variable
 int main = 0;
     ^~~~
+ g++-7 --version
g++-7 (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ g++-7 c.cpp
c.cpp:1:5: error: cannot declare ‘::main’ to be a global variable
 int main = 0;
     ^~~~
+ g++-8 --version
g++-8 (Ubuntu 8.3.0-6ubuntu1~18.04.1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ g++-8 c.cpp
c.cpp:1:5: error: cannot declare ‘::main’ to be a global variable
 int main = 0;
     ^~~~

Note: I already come across this but I doesn't answer my questions. Let me know if I need to add any specific tag to get attention of person with knowledge of this particular problem.

Manthan Tilva
  • 3,135
  • 2
  • 17
  • 41
  • `int main = 0;` should not compile live: https://godbolt.org/z/uh3nm6 – Richard Critten Nov 29 '19 at 09:28
  • @RichardCritten I didn't say it is compiling every time. Check version details of compiler I mention on question. – Manthan Tilva Nov 29 '19 at 09:32
  • @RichardCritten And It is not for clang. It is for gcc. – Manthan Tilva Nov 29 '19 at 09:33
  • 6
    _"...the name main in the global namespace is reserved for functions..."_: source: https://en.cppreference.com/w/cpp/language/main_function – Richard Critten Nov 29 '19 at 09:35
  • 10
    If you're using the name `main` for a variable, you're doing it wrong. It's undefined behaviour. Don't waste your time investigating why it compiles on certain compiles and not on others and why it segfaults – Jabberwocky Nov 29 '19 at 09:38
  • @RichardCritten this question is less about standard and more about compiler and behavior – Manthan Tilva Nov 29 '19 at 09:38
  • 1
    @ManthanTilva if you really want to find out what happens, look at the [generated assembly output](https://godbolt.org/z/TqvSVm). No code is actually generated and the code that will be executed is whatever junk is in memory. – Jabberwocky Nov 29 '19 at 09:42
  • 3
    Undefined behavior is behavior that is undefined. It's like tossing down a bottle from a skyscraper, then afterwards go down on the street to see what damage it caused, if any. During some circumstances it was crash into cars, in some cases it will hit a pedestrian, in other cases nobody gets hurts. Who cares why, stop throwing bottles. Just because the owner of the skyscraper has not banned you from using the elevator, it doesn't mean that they take any responsibility for you throwing bottles nor will they ensure that your bottles fly in some deterministic manner. The skyscraper is just fine. – Lundin Nov 29 '19 at 10:12
  • Famous mechanisms at work: garbage in garbage out... – Gerhardh Nov 29 '19 at 11:12
  • @RichardCritten compile as **`C`** not C++ – 0___________ Nov 29 '19 at 12:34
  • @P__J__ Am following the [C++] tag and not the [C] tag; also OP say `g++` so I missed the `C` part. – Richard Critten Nov 29 '19 at 12:36

4 Answers4

8

A program with such a declaration

int main = 0;

in the global namespace (or file scope in C) is ill-formed.

More modern compilers can issue a compile-time error.

From the C++ 17 Standard (6.6.1 main function)

  1. … 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 name main is not otherwise reserved.

You might use such a declaration in a C++ program for example the following way

namespace Name
{
    int main = 0;
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

Part of the explanation for changes between compilers is that the constraints on main have changed between C++ standards.

C++98 (section 3.6 para 3) says

The function main shall not be used (3.2) within a program. The linkage (3.5) of main is implementation-defined. A program that declares main to be inline or static is ill-formed. The name main is not otherwise reserved.

C++11 says essentially the same thing - except it removes the reference to Section 3.2 and also disallows main being constexpr (consistent with the fact that C++11 introduced constexpr).

From this, I would suggest that - before C++11 - compiler implementers had plenty of freedom about what to do if code defined a variable at file scope named main. Practically, I'm inclined to further suggest they may not have thought about that particular case at all but - if queried on a program compiling and crashing - they could probably make a claim of undefined behaviour. One type of undefined behaviour occurs when the standard simply doesn't constrain what happens.

C++17, moves the discussion of the main function to Section 6.6.1. In para 3 of that section it says (bold highlighting mine, of text that was not in an earlier standard)

The function main shall not be used within a program. The linkage (6.5) of main is implementation-defined. A program that defines main as deleted or that declares main to be inline, static, or constexpr is ill-formed. The main function shall not be declared with a linkage-specification (10.5). 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 name main is not otherwise reserved.

From C++17, defining a variable at file scope named main at file scope therefore makes a program ill-formed - which then means an implementation may diagnose an error.

Peter
  • 35,646
  • 4
  • 32
  • 74
1

For C, using main as a variable is undefined and can be caught through syntax, so all compilers should diagnose this. C17 says

The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters: ... etc

and then come the two possible prototypes for main as a function.

The shall here is important, it makes it explicitly undefined to use the identifier main differently.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
1

There are two slightly different questions here:

  1. Why is int main = 0; wrong?

  2. If int main = 0; is wrong, why do different compilers treat it differently?

Before answering either question, it's worth making an oft-repeated analogy: A Programming Standard (like that for C or C++) is a lot like a contract between you, the programmer, and the programmers who wrote the compiler you're using. If you follow all the rules in the contract when you write your program, and if the compiler writers followed all the rules when they wrote your compiler, everything should work fine. But if any rules get broken on either side, things go wrong.

Now, most of the rules in a programming language contract are sort of conditional: If you want to add two numbers, the operator you use is +. You don't get to decide you want to use the keyword add; the language says you use the symbol +, and that's that.

Some of the rules in a programming language contract are absolute, and negative, in that they tell you what you must not do. You must not add a pointer and a floating-point value.

But there are a very few rules — I can really only think of one — that are absolute and positive, in that they tell you what you must do, whether you want to or not. The one rule I can think of concerns the entry point of your program. You must have an entry point function, its main must be main, its return value must be int, and it must accept either zero parameters, or two: one of type int and one of type char **. (You do get to pick your own names for those parameters, although it's conventional to name them argc and argv.)

So when you wrote

int main = 0;

you broke that rule, albeit in an unusual way: you did have something named main, but it was an integer, not a function.

If this is still perplexing to you, consider this example. Suppose you write a file main.c containing:

#include <stdio.h>

extern int f();

int main()
{
    printf("About to call function f() ...\n");
    f();
    printf("back from function f().\n");
}

You've got a very simple main function, calling a function f which is presumably defined in a separate source file. And suppose you do create that separate source file, f.c, containing

char f[] = "Hello, world!";

Obviously there's a pretty gross mismatch here between how you externally declared f in main.c, and how you actually defined it in f.c.

But if you compile main.c and f.c using a C compiler, and link the resulting object files together with a conventional linker, it's likely to give no errors. (I tried it just now, and got none.) But it crashes when it runs, for the obvious reason.

The question of whether a compiler might actually complain about the "gross mismatch" depends on a number of things. Traditionally, C compilers were very generic about the code they compiled, meaning that no names were special. If you declared something named main that's improperly an array instead of a function, typically the compiler wouldn't notice. And by the time you're linking together separately-compiled object files, all the linker knows about (again, based on traditional object file formats) is that there's something at an address identified by the identifier main; the linker has no way of knowing the stuff at main isn't properly-compiled machine language code corresponding to a callable function.

More recently, compilers have begun making use of the guarantees afforded them by the Standard, and "learning" abut Standard-imposed identifiers, including main. And indeed two different modern compilers I tried complained "variable named 'main' with external linkage has undefined behavior".

And when it comes to C++, things get more complicated still. Typically, the linker does not just know that "there's something at an address identified by an identifier", typically there's extra information (if only via "mangled names") by which the linker can tell the difference between an identifier identifying a blob of memory containing some data, versus an identifier identifying a blob of memory containing some compiled machine instructions.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103