1

On cppreference.com I found the following code example:

#include <iostream>
#include <string_view>
 
// Print a string surrounded by single quotes, its
// length and whether it is considered empty.
void check_string(std::string_view ref)
{
    std::cout << std::boolalpha
              << "'" << ref << "' has " << ref.size()
              << " character(s); emptiness: " << ref.empty() << '\n';
}
 
int main(int argc, char **argv)
{
    // An empty string
    check_string("");
 
    // Almost always not empty: argv[0]
    if (argc > 0) // <--- is this necessary?
        check_string(argv[0]);
}

Is the test argc > 0 necessary if I have a program that runs on Linux, macOS, Windows, Android or any other common operating system? As far as I know, under these environments the first argument is always the name of the program itself.

Is there an environment where argc can be equal or even less than 0? More precisely, would argc be 0 in a freestanding environment (i.e. without an operating system), for example?

Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
  • 1
    The 1973 version of **C** did not have `unsigned`. Between 1973 to 1980, the **C** language got `unsigned`, `long`, `union`, and `enum`. I suspect the reason that **argc** is an `int` is because `unsigned` wasn't an option when the convention was established. – Eljay Mar 19 '23 at 21:20
  • 2
    "_More precisely, would argc be 0 in a freestanding environment_": I don't think freestanding changing anything (aside from there potentially being no `main` at all). The meaning of "_name used to invoke the program_" becomes even less defined without an OS environment, but what is passed to your freestanding program would basically be implementation-defined, something to look up in the compiler documentation. – user17732522 Mar 19 '23 at 21:44
  • @user17732522 Okay, if in such an environment `main` the entry point may change, than that answers my question. Thanks for pointing out! – Benjamin Buch Mar 19 '23 at 21:51

1 Answers1

6

As far as I know, under these environments the first argument is always the name of the program itself.

In practice this is often only a convention because the parent process can freely decide what (if any) arguments it passes a new child process e.g. via the exec* family calls or analogues OS interfaces.

At least Linux before v5.18 and Windows (see comments) place no restrictions on what arguments the parent passes to the child, if any, but the OS may also be stricter.

In particular, because argc == 0 has caused security vulnerabilities in the past, Linux forces an additional empty string since v5.18 in argv (and setting argc to 1) if argc would be 0 otherwise. See commit and LWN article discussing this change, the vulnerabilities and programs previously relying on argc == 0 being allowed.

The C++ standard does say that, if argc >= 1, then argv[0] should be an empty string or "the name used to invoke the program". See [basic.start.main]/2 for reference. But I don't think this can have any real normative meaning, because there is no definition of what such a name would be. It does however show that that the convention is supposed to be followed if there are any arguments given. It still allows argc == 0 without any constraints though.

POSIX goes into slightly more detail by saying that "The value in argv[0] should point to a filename string that is associated with the process being started" when calling one of the exec* family calls. I think "should" does however not imply a strict requirement in the context of POSIX specification and I don't see any "shall" statement requiring at least one argument. In fact POSIX contains a rationale (see same link) explaining that early POSIX/C standard proposals contained such a requirement, but were dropped. The "should" requirement applies only to Strictly Conforming POSIX Applications.

In any case argc cannot be negative. See [basic.start.main]/2.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • 2
    On Windows, `argc` can be 0 if a child process is executed via `CreateProcess()` where `lpApplicationName` is the child exe and `lpCommandLine` is empty. – Remy Lebeau Mar 19 '23 at 21:40
  • @RemyLebeau Have you tested that? (I don't have a Windows system available to test.) I realized that Linux actually changed the behavior about a year back for security reasons. – user17732522 Mar 19 '23 at 22:07
  • https://stackoverflow.com/a/32789751/65863 – Remy Lebeau Mar 19 '23 at 22:14