0

From ISO/IEC 9899:2024, 5.1.2.3.2, Program startup:

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;6) or in some other implementation-defined manner.

And a footnote at the end of the page says:

  1. Thus, int can be replaced by a typedef name defined as int, or the type of argv can be written as char ** argv, or the return type may be specified by typeof(1), and so on.

From this, I conclude that the prototype for main() can be any of the following:

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

/* Because function declarations whose parameter list is empty is treated the same 
   as a parameter list that contains only a single void in C23. */
2. int main() { /* ... */ }       

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

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

/* Or any other value than 1 that fits in the range of an int. */
5. typeof(1) main() { /* ... */ }  /* And all the other aforementioned variants as well. */

6. typedef int val;
   val main(val argc, char **argv) { /* ... */ } /* And all the other aforementioned variants as well. */

Are there any other types that are equivalent? @Davislor at codereview.stackexchange.com says that (in the comments):

And 6.7.6.3 says that, in a function declaration, *argv[] and const **argv are “compatible types.”

6.7.6.3 is too dense for me to make sense of. Is the following:

7. int main(int argc, char const **argv) { /* ... */ }

a valid prototype for main()? If so, what about:

int main(const int argc, char **const argv) { /* ... */ }
int main(int argc, char **const volatile _Atomic argv) { /* ... */ }

And other compatible types, if any?

5
  • What I would really prefer to see is a list of all correct prototypes, so that I don't claim an outlandish one is incorrect during a code review, only to have someone tell me that the C Standard says elsewise. :)
    – Harith
    Commented May 9 at 7:50
  • 1
    I would accept version 1 without questions, For 3 and 4, I would ask about how the parameters are used. Anyone trying 5 or 6 would get a warning, and be fired if repeated.
    – BoP
    Commented May 9 at 8:37
  • 6.7.6.3 does not say *argv[] and const **argv are compatible types. What it does say means that parameter declarations of T *argv[], T *argv[const], and T ** const argv would be taken as the same when considering function compatibility. Note that the qualifier on the parameter directly is removed when considering compatibility, not the qualifier on what the parameter points to or any further levels of indirection. Your link is just to codereview.stackexchange.com, not to the place where @Davislor made this statement. You should give a full URL to it so it can be corrected. Commented May 9 at 11:13
  • Specifically, 6.7.6.3 14 says “… In the determination of type compatibility and of a composite type,… each parameter declared with qualified type is taken as having the unqualified version of its declared type.” Effectively, a qualifier on a parameter affects things only inside the function; it affects only how the parameter is used inside the function. It does not affect compatibility between function declarations. A reason for this is that qualifiers only affect objects—the memory of a const object is not modified, the memory of a volatile object must be accessed each time, and so on… Commented May 9 at 11:17
  • … But arguments passed to functions are values, not objects. When a function call is made, the value is passed. Then, as specified by the C standard, when function execution is starting, each parameter (an object) is assigned the value of the argument. So how the function handles its parameters is solely internal to the function. The arguments are just values and so effectively have no qualifiers. Passing an argument to a function that treats its parameter as const is exactly the same as passing an argument to a function that treats its parameter as non-const. Commented May 9 at 11:17

1 Answer 1

2
  • 7th point contradicts

The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination.

IMO it prevents this form of main function

4
  • Even if the program is allowed to modify the parameters, it is not required to do that. Making them const signals an intention.
    – BoP
    Commented May 9 at 8:39
  • 1
    @BoP - indeed, but the intention of the Standard is to have them modifiable. So the programmer shall not change it. (IMO)
    – gulpr
    Commented May 9 at 8:42
  • "shall be modifiable by the program": int main(int, const char** argv) { ((char*) argv[0])[0] = 'b'; }: it's still modifiable. I still think it's one of the implementation-defined prototypes, because const char** is not "equivalent" to char*[] like char** is.
    – Artyer
    Commented May 10 at 18:30
  • @Artyer no it is an example of not understanding what const is, and how to use it
    – gulpr
    Commented May 10 at 21:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.