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.
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 it's not guaranteed.
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.
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;
}
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 assumeargv[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
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.