1

Preface and the problem

I'm currently studying C++ programming language and game programming. At the moment, I'm working on a simple game engine just to practice 'consistency' and architecture of the API, and due to this reason the idea of mimicing C# 'Program' class appeared.

C# Entry point:

class Program
{
    static void Main(string[] args)
    {
        // Do stuff.
    }
}

C++ analogue required:

class Program
{
public:
    static void Main()
    {
        // Do stuff. 'args' analogue can be ignored, if necessary.
    }
};  

Is it possible to somehow, using linker options, redefine entry point to be a static class method?

Related experience and my theories on this topic

  1. The main reason, why I think, this should be possible is described in the following piece of code (that was successfully compiled using mingw-w64).
#include <iostream>

class Main
{
public:
    static void Foo() { std::cout << "Main::Foo\n"; }
};

void localFoo() { std::cout << "localFoo\n"; }

void callFunc(void(*funcToCall)())
{
    funcToCall();
}

int main()
{
    callFunc(localFoo);
    callFunc(Main::Foo); // Proves that Main::Foo has the same interface as localFoo.

    return 0;
}
  1. (Refers to Win32 API) I abstracted Win32 API into classes and used window procedure as a static member of class. It was absolutely correct to Win32 WNDCLASS and I could even use static members of my class inside this procedure.

Conslusion I made: static fields and methods technically have no differences between global variables and functions, and, since that, they can replace some code, that dates back to C (default entry point, for example).

Notes

  • Both MinGW and MSVC (Visual Studio or cmd) solutions are acceptable.
  • The author of the post is extremely grateful for any information provided :3
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Leo
  • 21
  • 1
  • 2
  • 6
    Why not provide the linker with an additional object file compiled from a source file which has a `int main` which calls the `static` member you want? – François Andrieux Feb 22 '21 at 20:47
  • 2
    Trying to make C++ "consistent" with C# would be an exercise in futility. Give it up. Having said that, you probably want something like [this](https://stackoverflow.com/questions/7494244/how-to-change-entry-point-of-c-program-with-gcc), but will need to provide a mangled name according to the mangling rules. – rustyx Feb 22 '21 at 20:51
  • I never dove too deep into the topic but the fact that console and windowed applications (on windows) use different entry points would suggest to me that it is indeed possible. Besides that you can do what @Francois said, or you can use dependency injection (in case you plan to create an engine and want to keep control over main yourself) – Kami Kaze Feb 22 '21 at 20:53
  • 6
    This is a variant of the old saying "an engineer can write FORTRAN in any language." (I'm an engineer, and see the truth in what I've seen) Take inspiration from other languages, and good practices, but don't try and replicate things exactly. When I write Python, I code one way, C++ another, and C# another way again. Heck even C and C++ have different "good ways" of structuring things. – Kevin Anderson Feb 22 '21 at 20:55
  • 2
    A static method for an entry point is Java's "solution" to being "pure OOP" and "better than C++ in every way". That's what happens when designing out of spite. When doing C++, embrace the C++ way, and free your functions when appropriate. – StoryTeller - Unslander Monica Feb 22 '21 at 20:55
  • @KamiKaze I've never actually seen that. Every C++ program I've written has required a main, but I certainly haven't programmed every different flavor of C/C++. Most of my GUI work has been in X11 and Qt. – Joseph Larson Feb 22 '21 at 20:56
  • 3
    @KamiKaze for all I know the `winmain` is called by a `main` buried somewhere out of sight. – user4581301 Feb 22 '21 at 20:56
  • "Is it possible" -- yes. Do go ahead and study the startup code which eventually calls `main()`, it's interesting to see and observe. However, I think your initial goal is futile. One reason is that it simply goes against the language. The other is that this doesn't need to scale, it's a simple piece of code you write once and never modify much after that, so don't over-engineer it. – Ulrich Eckhardt Feb 22 '21 at 20:56
  • It has been a while, but as far as i can remember I had to change the entry point when creating a windowed application and not wanting to have a cmd pop open aswell. Could be that the 'no console' part was reason for that @JosephLarson, user4581301 – Kami Kaze Feb 22 '21 at 20:59
  • 1
    @Francois, Already implemented this kind of entry point (for client programmer it looks like an entry point), just was looking for more flexible and native-looking stuff. For Windows applications I usually don't use ```WinMain```, or default ```main```. There's one more variant of ```main``` that accepts both argc, argv and hInstance with lpCmdLine in its signature. – Leo Feb 22 '21 at 21:06
  • 1
    Unless you are in a free-standing environment, you are required to have a single main function: https://timsong-cpp.github.io/cppwp/basic#start.main-1 – NathanOliver Feb 22 '21 at 21:18
  • 1
    MSVC has the `/ENTRY` linker option. I'm not sure if name mangling will factor into this though... the static member function may be name mangled into something unrecognizable and you may need to pass that to the linker instead. – Dean Johnson Feb 22 '21 at 21:53
  • 1
    @Dean I tried -Wl,-e option in MinGW and tried to use it like ```-Wl,-eProgram::Main``` but as I'd expected it didn't work. After that I used -S flag to check what name this static method has in assembly and then passed it to linker as i did before, but it didn't work again. Actually, with all this complicated things it seems to be a really inefficient activity, trying to change this. As @Ulrich mentioned, there's no point in doing all this stuff just to change the entry point. – Leo Feb 22 '21 at 22:35
  • 2
    @user4581301 the "true" entry point is set by the linker in the executable's PE header. That is the entry point that the OS actually calls. When linking to the compiler's runtime library, whichever version of the runtime is used (console vs GUI, etc), that defines which library entry point is used in the PE header. That entry point in turn performs any necessary startup logic (init globals, read command-line parameters, etc) and then calls the user's `main()` or `WinMain()` function with appropriate input parameters as needed. – Remy Lebeau Feb 23 '21 at 00:24
  • @Federico How does the `int main() { Program::Start(); }` suggestion not work for you? – 1201ProgramAlarm Jul 23 '21 at 20:24
  • @1201ProgramAlarm It works indeed. We ´ve that entry point in our project from day 1. But other collaborators wanted to go pure OOP Java/C# style (w/ which I disagree). But this, as I expected, can´t be done w/o breaking things and not being able to use the C++ runtime library as Paul Sanders pointed out. – Federico R. Figueredo Jul 24 '21 at 18:13

1 Answers1

1

Is it possible to somehow, using linker options, redefine entry point to be a static class method?

No. Not if you want to use the C++ runtime library, at any rate. main (or WinMain) is called by the runtime library once it has completed initialising itself, and that call is hard-coded in the runtime library itself.

The MSVC linker lets you specify an alternative entry point with the /ENTRY switch (see here), but if you do that you will bypass the runtime library initialisation code and that will break things.

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48