Can argc be zero on a POSIX system?

前端 未结 6 1399
暖寄归人
暖寄归人 2021-02-04 23:04

Given the standard definition for the main program:

int main(int argc, char *argv[]) {
   ...
}

Under which circumstances can argc

相关标签:
6条回答
  • 2021-02-04 23:26

    whenever you want to run any executable like ./a.out it will have one argument thats the program name. But It is possible to run a program with argc as zero in Linux, by executing it from another program that calls execv with an empty argument list.

    for e.g

    int main() {
        char *buf[] = { NULL };
        execv("./exe", buf); /* exe is binary which it run with 0 argument */
        return 0;
    }
    
    0 讨论(0)
  • 2021-02-04 23:30

    Early proposals required that the value of argc passed to main() be "one or greater". This was driven by the same requirement in drafts of the ISO C standard. In fact, historical implementations have passed a value of zero when no arguments are supplied to the caller of the exec functions. This requirement was removed from the ISO C standard and subsequently removed from this volume of POSIX.1-2017 as well. The wording, in particular the use of the word should, requires a Strictly Conforming POSIX Application to pass at least one argument to the exec function, thus guaranteeing that argc be one or greater when invoked by such an application. In fact, this is good practice, since many existing applications reference argv[0] without first checking the value of argc.

    The requirement on a Strictly Conforming POSIX Application also states that the value passed as the first argument be a filename string associated with the process being started. Although some existing applications pass a pathname rather than a filename string in some circumstances, a filename string is more generally useful, since the common usage of argv[0] is in printing diagnostics. In some cases the filename passed is not the actual filename of the file; for example, many implementations of the login utility use a convention of prefixing a ( '-' ) to the actual filename, which indicates to the command interpreter being invoked that it is a "login shell".

    Also, note that the test and [ utilities require specific strings for the argv[0] argument to have deterministic behavior across all implementations.

    Source


    Can argc be zero on a POSIX system?

    Yes but it would not be strictly conforming to POSIX.

    0 讨论(0)
  • 2021-02-04 23:34

    To add to the other answers, there is nothing in C (POSIX or not) preventing main() from being called as a function within the program.

    int main(int argc, int argv[]) {
        if (argc == 0) printf("Hey!\n");
        else main(0,NULL);
    
        return 0;
    }
    
    0 讨论(0)
  • 2021-02-04 23:36

    TL;DR: Yes, argv[0] can be NULL, but not for any good/sane reason I know of. However, there are reasons not to care if argv[0] is NULL, and to specifically allow the process to crash if it is.


    Yes, argv[0] can be NULL on a POSIX system, if and only if it was executed without any arguments.

    The more interesting practical question is, should your program care.

    The answer to that is "No, your program can assume argv[0] is not NULL", because some system utilities (command-line utilities) either do not work or work in a non-deterministic fashion, when argv[0] == NULL, but more importantly, there is no good reason (other than stupidity or nefarious purposes) why any process would do that. (I'm not sure if the standard usage of getopt() also fails then — but I would not expect it to work.)

    A lot of code, and indeed most examples and utilities I write, begin with the equivalent of

    int main(int argc, char *argv[])
    {
        if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
            printf("Usage: %s [ -h | --help ]\n", argv[0]);
            /* ... print usage ... */
            return EXIT_SUCCESS;
        }
    

    and this is reasonable and acceptable, because there is no good reason for a process to exec another process without providing at least the command path being executed, i.e. execlp(cmd, cmd, NULL) rather than execlp(cmd, NULL).

    (However, I can think of a few nefarious reasons, like exploiting timing race windows related to pipe or socket commands: an evil process sends an evil request via an established Unix domain socket, and then immediately replaces itself with an authorized victim command (run without any arguments, to ensure minimum start-up time), so that when the service getting the request checks the peer credentials, it sees the victim command, instead of the original evil process. It is, in my opinion, best for such victim commands to crash hard and fast (SIGSEGV, by dereferencing a NULL pointer), rather than try and behave "nicely", giving the evil process a larger time window.)

    In other words, while it is possible for a process to replace itself with another but without any arguments causing argc to be zero, such behaviour is unreasonable, in the strict sense that there is no known non-nefarious reason to do so.

    Because of this, and the fact that I love making life hard for nefarious and uncaring programmers and their programs, I personally will never add the trivial check, similar to

    static int usage(const char *argv0)
    {
        /* Print usage using argv0 as if it was argv[0] */
        return EXIT_SUCCESS;
    }
    
    int main(int argc, char *argv[])
    {
        if (argc < 1)
            return usage("(this)");
        if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
            return usage(argv[0]);
    
        /* argv[0] and argv[1] are non-NULL, argc >= 2 */
    

    except if requested by someone with a particular existing use case in mind. And even then I'd be a bit suspicious, wanting to verify the use case myself first.

    0 讨论(0)
  • 2021-02-04 23:37

    Yes, it is possible. If you call your program as follows:

    execl("./myprog", NULL, (char *)NULL);
    

    Or alternately:

    char *args[] = { NULL };
    execv("./myprog", args);
    

    Then in "myprog", argc will be 0.

    The standard also specifically allows for a 0 argc as noted in section 5.1.2.2.1 regarding program startup in a hosted environment:

    1 The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters:

    int main(void) { /* ... */ } 
    

    or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):

    int main(int argc, char *argv[]) { /* ... */ }
    

    or equivalent; or in some other implementation-defined manner.

    2 If they are declared, the parameters to the main function shall obey the following constraints:

    • The value of argc shall be nonnegative.
    • argv[argc] shall be a null pointer.

    ...

    Note also that this means that if argc is 0 then argv[0] is guaranteed to be NULL. How printf treats a NULL pointer when used as the argument to a %s specifier is not spelled out in the standard however. Many implementations will output "(null)" in this case but I don't believe it's guaranteed.

    0 讨论(0)
  • 2021-02-04 23:41

    Yes, it can be zero, meaning that argv[0] == NULL.

    It's a convention that argv[0] is the name of the program. You can have argc == 0 if you launch yourself the binary, like with execve family and don't give any argument. You can even give a string that is nowhere near to be the program name. That's why using argv[0] to get the name of the program is not entirely reliable.

    Usually, the shell where you type your command-line always add the program name as the first argument, but again, it's a convention. If argv[0] == "--help" and you use getopt to parse option, you will not detect it because optind is initialized to 1, but you can set optind to 0, use getopt and "help" long option will show up.

    long story short : It's perfectly possible to have argc == 0 (argv[0] is not really special by itself). It happen when the launcher doesn't give argument at all.

    0 讨论(0)
提交回复
热议问题