4

Calling maininside your program violates the C++ Standard

void f()
{
    main(); // an endless loop calling main ? No that's not allowed
}

int main()
{
    static int = 0; 
    std::cout << i++ << std::endl;
    f(); 
}

In a lecture Chandler Carruth, at about '22.40' says

if you've written a compiler test you've written a call to main

How is this relevant or how the fact that the Standard doesn't allow is overcome ?

Community
  • 1
  • 1
Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
  • 3
    It's forbidden by the c++ standard. `main()` is reserved as the entry point of the application, and calling it explicitly is UB. – πάντα ῥεῖ Sep 05 '15 at 07:48
  • 8
    PS: If you ever need to unit test a source file that contains "main()", a trick for doing this is to 1) code your unit test (which must have it's own "main()" somewhere), 2) `#include "myfile.cpp"` (so the unit test can invoke your code), 3) before the "include", add `#define main FooMain`, 4) after the "include", add `#undef main`, and finally 5) have your test call `FooMain()` – paulsm4 Sep 05 '15 at 08:04
  • 2
    @paulsm4 Write that down in an answer please. – πάντα ῥεῖ Sep 05 '15 at 08:10
  • 3
    @paulsm4 isn't `#define main FooMain` undefined behavior as well? – The Paramagnetic Croissant Sep 05 '15 at 08:42
  • I get what he generally meant: having cycles that span across your program is bad and an example is a call to main. But I don't get how it relates to compiler tests. – edmz Sep 05 '15 at 09:25
  • That talk is about compilers, and not 100% about C++. It's also not about frontends but the optimizer part. You shouldn't take that statement as a comment about C++. – Mat Sep 05 '15 at 09:27
  • 1
    @The It's UB to #define a keyword, but I think `main` is fair game. – Alan Stokes Sep 05 '15 at 09:43
  • 1
    If you're writing a compiler test you probably know what that specific compiler actually does with a call to `main `; the fact that the standard imposes no requirements doesn't matter in that case. – Alan Stokes Sep 05 '15 at 09:45

1 Answers1

4

The point here is that if you write compiler test-code, you probably will want to test calling main with a few different parameter sets and that it is possible to do this, with the understanding of the compiler you are going to test on.

The standard forbids calls to main so that main can have magical code (e.g. the code to construct global objects or to initialize some data structure, zero out global uninitialized POD data, etc.). But if you are writing test code for a compiler, you probably will have an understanding of whether the compiler does this - and if so, what it actually does in such a step, and take that into account in your testing - you could for example "dirty" some global variable, and then call main again and see that this variable is indeed set to zero again. Or it could be that main is indeed not callable in this particular compiler.

Since Chandler is talking about LLVM (and in C terms, Clang), he knows how that compiler produces code for main.

This clearly doesn't apply to "black box testing" of compilers. In such a test-suite, you could not rely on the compiler doing anything in particular, or NOT doing something that would harm your test.

Like ALL undefined behaviour, it is not guaranteed to work in any particular way, but SOMETIMES, if you know the actual implementation of the compiler, it will be possible to exploit that behaviour - just don't consider it good programming, and don't expect it to work in a portable way.

As an example, on a PC, you can write to the text-screen (before the MMU has been configured at least) by doing this:

 char *ptr = (char *)0xA0000;
 ptr[0] = 'a';
 ptr[1] = 7;   // Determines the colour. 

This, by the standard, is undefined behaviour, because the standard does say that you can only use pointers to allocations made inside the C or C++ runtime. But clearly, you can't allocate memory in the graphics card... So technically, it's UB, but guess what Linux and Windows do during early boot? Write directly to the VGA memory... [Or at least they used to some time ago, when I last looked at it]. And if you know your hardware, this should work with every compiler I'm aware of - if it doesn't, you probably can't use it to write low-level driver code. But it is undefined by the standard, and "UB sanitizer" will probably moan at the code.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227