Search code examples
c++windowscommand-line-argumentsmsvc12

Issues with C++ command-line arguments on Windows


I'm somehow having issues parsing command-line arguments on Windows in C++. I tried using this

int main(int argc, char **argv)
{
    std::cout << "Command-line argument count: " << argc << " \n";
    std::cout << "Arguments:\n";
    for (int i = 0; i < argc; i++)
        std::cout << "  argv[" << i << "]   "
        << argv[i] << "\n";

    return 0;
}

as well as this

int main(int argc, char *argv[])
{
    std::cout << "Command-line argument count: " << argc << " \n";
    std::cout << "Arguments:\n";
    for (int i = 0; i < argc; i++)
        std::cout << "  argv[" << i << "]   "
        << argv[i] << "\n";

    return 0;
}

The variables argc and argv seem to be somehow uninitialized. That's what launching the program returns to me:

Z:\Dev\ProcessSuspender\Debug>ProcessSuspender a
Command-line argument count: 2130558976
Arguments:
  argv[0]
  argv[1]   ╠ÉÉÉÉÉj↑h╚♂YwÞØ÷■ âe³
  argv[2]

(crash following)

I compiled it with MSVC12 using the /SUBSYSTEM:CONSOLE linker option. What could be the cause of this issue?


Solution

  • I've manually set the entry point to main. Whether I use the default project setting (_tmain) or not, the issue persists.

    In general, you should not do that unless you know the consequences. The typical values of the entry point (/ENTRY) should be either:

    • [w]mainCRTStartup, which calls [w]main, or
    • [w]WinMainCRTStartup, which calls [w]WinMain, or
    • _DllMainCRTStartup, which calls DllMain.

    Why is this needed? Well, the …CRTStartup-family of functions do a couple crucial things, including the initialization of:

    • the C runtime (CRT),
    • any global variables, and
    • the arguments argc and argv, as you've accidentally found out.

    So for a typical program you probably want it to do its job. In the Linux world, there is an equivalent function called _start that is needed to do the same initialization tasks as well, which can be overridden with -e while linking.

    The confusion here probably stems from difference in ambiguous meaning of the word "entry point": there is the meaning of "apparent entry point" from the perspective of the language (which is main and its ilk), and the meaning of the "true entry point" from the perspective of the language implementation (which is …CRTStartup or _start).

    Note that using the …CRTStartup functions is not absolutely essential, as you can certainly write a program that avoids using them. It does come with a cost, however:

    • you can't use the C runtime, so you can't use most of the standard library,
    • you need to manually initialize any global variables, and
    • you need to manually obtain argc and argv using the Windows API (GetCommandLineW and CommandLineToArgvW).

    Some do this to avoid dependency on the CRT, or to minimize the executable size.