1

I often see programs where people put argc and argv in main, but never make any use of these parameters.

int main(int argc, char *argv[]) {
    // never touches any of the parameters
}

Should I do so too? What is the reason for that?

Kaiyakha
  • 1,463
  • 1
  • 6
  • 19
  • 1
    [GNU conventions](https://www.gnu.org/prep/standards/standards.html) are suggesting to understand at least `--version` and `--help`. I recommend to follow that. My opinion is that not parsing `argv` with `argc` is a mistake – Basile Starynkevitch Jun 17 '22 at 07:48
  • @BasileStarynkevitch what do these options have to do with `argc` and `argv`? Could you please be more explicit? – Kaiyakha Jun 17 '22 at 07:53
  • 1
    These are *conventions* but I find them helpful. And they are related to `argc` and `argv`. My opinion is that following them is useful. Try `/bin/grep --help` and `/bin/grep --version` on your Linux laptop. See chapter about [Parsing program arguments](https://www.gnu.org/software/libc/manual/html_node/Parsing-Program-Arguments.html) – Basile Starynkevitch Jun 17 '22 at 07:56
  • @BasileStarynkevitch my laptop is on Windows – Kaiyakha Jun 17 '22 at 07:59
  • 1
    Many GNU utilities are running on Windows and obey these conventions too on Windows – Basile Starynkevitch Jun 17 '22 at 07:59
  • 1
    Some libraries, SDL being one of them, urge you to include those variables though you never use them in your code. – ssd Jun 17 '22 at 08:07
  • 1
    @BasileStarynkevitch Actually, Windows programs (that got a WinMain/Wndproc) use an entirely different, implementation-defined form of main() such as `INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow)`, where command-line arguments are passed through `lpCmdLine`. It doesn't resemble standard C main() the slightest. – Lundin Jun 17 '22 at 09:38

2 Answers2

6

The arguments to the main function can be omitted if you do not need to use them. You can define main this way:

int main(void) {
    // never touches any of the parameters
}

Or simply:

int main() {
    // never touches any of the parameters
}

Regarding why some programmers do that, it could be to conform to local style guides, because they are used to it, or simply a side effect of their IDE's source template system.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • So when someone places parameters into `main` with no further use it is either for fun or because they don't know they can omit them? I mean I know I can omit them, I just can't understand why others do not omit them when they technically can. – Kaiyakha Jun 17 '22 at 07:25
  • 1
    No. If you enable full compiler warnings the compiler will flag `argc` and/or `argv` if the parameter is unused (`-Wunused`). Always compile with warnings enabled and many mysteries are made clear. – David C. Rankin Jun 17 '22 at 08:10
  • 1
    In addition to David's comment: You can omit the name of a parameter, and it will be inaccessible in the function body. Decent compilers will not produce diagnostics for such. But you have the list of arguments that the call can be checked against. `main()` receives commonly 2 arguments, an `int` and a pointer `char*` (actually to the first element of an array of `char*`), no matter what its body will use. – the busybee Jun 17 '22 at 08:25
  • @DavidC.Rankin: [`-Wunused` does not generate warnings for unused parameters in GCC or Clang.](https://godbolt.org/z/qq5rvcj3v) `-Wunused-parameter` is required. That is not included in `-Wall`, due to the frequency of situations in which there are good reasons not to use all parameters, so your advice to “Always compile with warnings enabled” is not helpful in this case. – Eric Postpischil Jun 17 '22 at 10:14
  • 3
    @thebusybee: Parameter names may be omitted in a function declaration, but omitting them in a function definition is a constraint violation. C 2018 6.9.1 5, about function definitions, says “If the declarator includes a parameter type list, the declaration of each parameter shall include an identifier, except for the special case of a parameter list consisting of a single parameter of type `void`,…” A conforming compiler may accept such code but it must issue a diagnostic message for the constraint violation. – Eric Postpischil Jun 17 '22 at 10:21
  • @EricPostpischil: this is unfortunate. Is there a proposal in C2x to relax this requirement? – chqrlie Jun 17 '22 at 10:25
  • In N2596, chapter 6.9.1: "_The declarator in a function definition specifies the name of the function being defined and the types **(and optionally the names)** of all the parameters;_" (emphasis by me). And "_Each parameter has automatic storage duration; its identifier, **if any,** is an lvalue._" with footnote 177: "_A parameter that has no declared name is inaccessible within the function body._" – the busybee Jun 17 '22 at 10:27
  • 2
    @thebusybee: N2596 is a draft and is not an official version of the standard. The text I quoted is from the current official version. – Eric Postpischil Jun 17 '22 at 10:33
  • @EricPostpischil It is included with `-Wextra -pedantic`. Which are included for full-warnings. Your critique is premature. – David C. Rankin Jun 18 '22 at 08:12
  • @DavidC.Rankin: Your comment indicates `-Wunused` will report unused parameters. As a matter of fact, that is incorrect. Instead of arguing your comment has merit, you could delete the incorrect information and write a new comment. – Eric Postpischil Jun 18 '22 at 12:10
  • @EricPostpischil: It's nice that the Standard is finally willing to relax a constraint that compilers should never have encouraged to enforce in the first place, but I think such things underscore a fundamental problem with the "C Standard" compared with other kinds of standards. With something like standard ammunition dimensions, each trait (e.g. distance from rear of cartridge to cartridge mouth) will have a nominal value, but have a separate specifications not only for the ranges of allowable lengths for conforming ammunition and lengths with which firearms must function correctly, ... – supercat Jun 18 '22 at 18:37
  • @EricPostpischil: ...but also specify a the ranges of lengths that validation tools must reject as too short, may but need not reject as too short, must accept, may but need not accept as too long, and must reject as too long. If the Standard had stated that compilers may accept or reject unnamed arguments (with accept being preferred), but validation tools must be configurable to reject them. – supercat Jun 18 '22 at 18:42
0

When you have a function, it's obviously important that the arguments passed by the caller always match up properly with the arguments expected by the function.

When you define and call one of your own functions, you can pick whatever arguments make sense to you for the function to accept, and then it's your job to call your function with the arguments you've decided on.

When you call a function that somebody else defined — like a standard library function — somebody else picked the arguments that function would accept, and it's your job to pass them correctly. For example, if you call the standard library function strcpy, you just have to pass it a destination string, and a source string, in that order. If you think it would make sense to pass three arguments, like the destination string, and the size of the destination string, and the source string, it won't work. You don't get to make up the way you'll call the function, because it's already defined.

And then there are a few cases where somebody else is going to call a function that you defined, and the way they're going to call it is fixed, such that you don't have any choice in the way you define it. The best example of this (except it turns out it's not such a good example after all, as we'll see) is main(). It's your job to define this function. It's not a standard library function that somebody else is going to define. But, it is a function that somebody else — namely, the C start-up code — is going to call. That code was written a while ago, by somebody else, and you have no control over it. It's going to call your main function in a certain way. So you're constrained to write your main function in a way that's compatible with the way it's going to be called. You can put whatever you want in the body of your main function, but you don't get to pick your own arguments: there are supposed to be two of those, an int and a char **, in that order.

Now, it also turns out that there's a very special exception for main. Even though the caller is going to be calling it with those two predefined arguments, if you're not interested in them, and if you define main with no arguments, instead, like this:

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

your C implementation is required to set things up so that nothing will go wrong, no problems will be caused by the caller passing those two arguments that your main function doesn't accept.

So, in answer to your question, many programs are written to accept int argc and char **argv because they're complying with the simple rule: those are the arguments the caller is accepting, so those are the arguments they believe their main function should be defined as accepting, even if it doesn't actually use them.

Programmers who define main functions that accept argc and argv without using them either haven't heard of, or choose not to make use of, the special exception that says they don't have to. Personally, I don't blame them: that special exception for main is a strange one, which didn't always exist, so since it's not wrong to define main as taking two required arguments but not using them, that could be considered "better style".

(Yes, if you define a function that fails to actually use the arguments it defines, your compiler might warn you about this, but that's a separate question.)

Steve Summit
  • 45,437
  • 7
  • 70
  • 103