8

What if I define main as a reference to function?

#include<iostream>
#include<cstring>

using namespace std;

int main1()
{
    cout << "Hello World from main1 function!" << endl;
    return 0;
}

int (&main)() = main1;

What will happen? I tested in an online compiler with error "Segmentation fault":

here

And under VC++ 2013 it will create a program crashing at run-time!

A code calling the data of the function pointer as a code will be compiled which will immediately crash on launch.

I would also like an ISO C++ standard quote about this.

The concept will be useful if you want to define either of 2 entry-points depending on some macro like this:

int main1();

int main2();

#ifdef _0_ENTRY
int (&main)() = main1;
#else
int (&main)() = main2;
#endif
AnArrayOfFunctions
  • 3,452
  • 2
  • 29
  • 66
  • _"What will happen? I tested in an online compiler with error 'Segmentation fault'"_ You just answered your own question, did you not?? – Lightness Races in Orbit Feb 12 '15 at 18:03
  • You're excluding freestanding implementations, correct? – Ben Voigt Feb 12 '15 at 18:03
  • It's not an ISO C++ standard quote but http://en.cppreference.com/w/cpp/language/main_function is usually pretty accurate. It says specifically that main is a special function and one of those 'special' properties is that it's address cannot be taken. – qeadz Feb 12 '15 at 18:03
  • 2
    I think you're asking for a lot to hope that the ISO standard comments on such an insane behavior. – David Hoelzer Feb 12 '15 at 18:03
  • @qeadz How do you take one's address in a declaration? –  Feb 12 '15 at 18:04
  • @DavidHoelzer: Why? It may be insane, but the point of an ISO standard is to specify such things in detail. – Christian Hackl Feb 12 '15 at 18:04
  • 1
    Amusingly, the standard doesn't actually prohibit code built within a freestanding implementation from defining a global symbol called `main` that is not a function, although it does impose other reservations on the symbol while in that namespace. – Lightness Races in Orbit Feb 12 '15 at 18:05
  • @qeadz: Nobody is taking the address of a function `main`, here. – Lightness Races in Orbit Feb 12 '15 at 18:05
  • 1
    @ChristianHackl The Standard already spans over 1300 pages. If it had to specify in detail every insane thing a programmer would want to do, nobody would read it. –  Feb 12 '15 at 18:06
  • @ChristianHackl For the same reason that the standard won't comment on the invalidity of many other oddball things that people might try to do. It doesn't try to comment on every case. It gives a standard framework of operations. – David Hoelzer Feb 12 '15 at 18:06
  • @DavidHoelzer: Actually it comments on every case that is allowed, and then it says the rest are UB. So that's pretty good coverage. By definition, the standard leaves nothing untouched (as long as you include "is UB" in your definition of "having been touched by the standard"). – Lightness Races in Orbit Feb 12 '15 at 18:08
  • @LightnessRacesinOrbit you are right. – qeadz Feb 12 '15 at 18:09
  • 1
    @remyabel: As a matter of fact, as the answers to the questions show, the standard *does* define whether the OP's code is allowed or not. It has to; by definition, the standard covers every imaginable piece of code and tells you whether it is valid or not. IWO, there is no piece of code, no matter how insane, of which the standard says "I don't care if this is undefined behaviour or not". – Christian Hackl Feb 12 '15 at 18:11
  • @ChristianHackl Where in the standard then does it say you can't declare a reference to `main`? Nowhere. It's implicitly prohibited. (And if something is blatantly missing from the standard, it's probably a defect.) –  Feb 12 '15 at 18:16
  • It is not a reference to 'main' but a global variable named 'main' which is a reference to function. I was mistaken too so changed question title. – AnArrayOfFunctions Feb 12 '15 at 18:19
  • 2
    @remyabel: It says that in [basic.start.main]/3. "The function `main` shall not be used within a program." That includes using it to initialise a reference. (Not that that has anything to do with the question, which is about what kind of entity `main` is allowed to be.) – Mike Seymour Feb 12 '15 at 18:20
  • @remyabel: Of course it's implicit, yes. The standard probably also does not say explicitly that `std::vector` does not have a `foo` member function, yet you can quote a passage which lists all member functions to explain why `v.foo()` is invalid. – Christian Hackl Feb 12 '15 at 18:20
  • Could you please integrate information into the question so that it forms a single coherent post? Rather than a timeline of edits.... – Lightness Races in Orbit Feb 12 '15 at 18:40

5 Answers5

16

That's not a conformant C++ program. C++ requires that (section 3.6.1)

A program shall contain a global function called main

Your program contains a global not-a-function called main, which introduces a name conflict with the main function that is required.


One justification for this would be it allows the hosted environment to, during program startup, make a function call to main. It is not equivalent to the source string main(args) which could be a function call, a function pointer dereference, use of operator() on a function object, or construction of an instance of a type main. Nope, main must be a function.

One additional thing to note is that the C++ Standard never says what the type of main actually is, and prevents you from observing it. So implementations can (and do!) rewrite the signature, for example adding any of int argc, char** argv, char** envp that you have omitted. Clearly it couldn't know to do this for your main1 and main2.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • 1
    Your quote is incomplete. Immediately thereafter is stated _"It is implementation-defined whether a program in a freestanding environment is required to define a main function."_ And there is no rule that such a program cannot define another kind of entity in the global namespace called `main` (p3: "A program that defines main as deleted or that declares main to be inline, static, or constexpr is illformed. The name main is not otherwise reserved. [ Example: member functions, classes, and enumerations can be called main, as can entities in other namespaces. —end example ]"). – Lightness Races in Orbit Feb 12 '15 at 18:06
  • That being said, I think we can assume the OP isn't using such an implementation. :) But perhaps all this would improve this answer? – Lightness Races in Orbit Feb 12 '15 at 18:08
  • @LightnessRacesinOrbit: It's interesting that they chose to write this rule as a universal statement followed by a contradiction, without so much as an "except". It surely wouldn't have been difficult to say "A program in a hosted environment shall contain a global function called `main`" or "A program shall contain a global function called `main`, except that in a freestanding environment it is implementation-defined..." – Ben Voigt Feb 12 '15 at 19:47
  • I agree. The wording has always bothered me (and seems to lead to a few internet arguments when it's subsequently misinterpreted!). – Lightness Races in Orbit Feb 12 '15 at 20:20
7

This would be useful if you want to define either of 2 entry-points depending on some macro

No, not really. You should do this:

int main1();
int main2();

#ifdef _0_ENTRY
   int main() { return main1(); }
#else
   int main() { return main2(); }
#endif
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
3

This is soon going to become clearly ill-formed, thanks to the resolution of CWG issue 1886, currently in "tentatively ready" status, which adds, among other things, the following to [basic.start.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.

T.C.
  • 133,968
  • 17
  • 288
  • 421
1

What will happen in practice is highly dependent on the implementation.

In your case your compiler apparently implements that reference as a "pointer in disguise". In addition to that, the pointer has external linkage. I.e. your program exports an external symbol called main, which is actually associated with memory location in data segment occupied by a pointer. The linker, without looking too much into it, records that memory location as the program's entry point.

Later, trying to use that location as an entry point causes segmentation fault. Firstly, there's no meaningful code at that location. Secondly, a mere attempt to pass control to a location inside a data segment might trigger the "data execution protection" mechanisms of your platform.

By doing this you apparently hoped that the reference will get optimized out, i.e. that main will become just another name for main1. In your case it didn't happen. The reference survived as an independent external object.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
0

Looks like you already answered the question about what happens.

As far as why, in your code main is a reference/pointer to a function. That is different than a function. And I would expect a segment fault if the code is calling a pointer instead of a function.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466