5
  1. I know that “the empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied[1]:

    // No information about the parameters is supplied.
    int foo();
    
  2. I know that “an empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters[2].

    // In this case the foo() function has no parameters.
    int foo()
    {
        // ...
    }
    
  3. I know that “the special case of an unnamed parameter of type void as the only item in the list specifies that the function has no parameters[3]:

    // foo() has no parameters.
    int foo(void);
    
    // bar() has no parameters.
    int bar(void)
    {
        // ...
    };
    

So here are some questions:

  1. Is int main() { /* ... */ } legal? The standard states[4] that

    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.

    So, is int main() { /* ... */ } is equivalent to int main(void) { /*... */ }?

  2. Why GCC allows pass parameters to a function that has no parameters?

    int foo();
    
    int bar()
    {
        return 42;
    }
    
    int main(void)
    {
        // Should be OK.
        foo(13);
    
        // Should give a compile-time error.
        bar(1, 12);
    }
    

    But I actually can compile the program with gcc version 10.1.0 (GCC): gcc -std=c17 -Werror -c test.c.


I've read some related questions, such as What are the valid signatures for C's main() function?, but they do not take into account the following standard clause[2]:

An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters.

So, is my understanding of this clause correct?


  1. ISO/IEC 9899:2017 § 6.7.6.3 / 14.
  2. ISO/IEC 9899:2017 § 6.7.6.3 / 14.
  3. ISO/IEC 9899:2017 § 6.7.6.3 / 10.
  4. ISO/IEC 9899:2017 § 5.1.2.2.1 / 1.
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
eanmos
  • 387
  • 1
  • 6
  • 15
  • The base philosophy of C (and C compilers) is that **"the programmers know what they are doing"** and if they do something *silly* UB allows anything to happen. So writing `int main() { ... }` is *silly*, but, generally, compilers do the right thing anyway without stepping into UB territory – pmg Jul 21 '20 at 18:06
  • 1
    Also: [Is int main() { } (without “void”) valid and portable in ISO C?](https://stackoverflow.com/q/29190986/1275169) – P.P Jul 21 '20 at 18:06
  • @EricPostpischil gcc will remove it in the future releases when someone will pay for it. (It is at the very end of the list as every change cost money and IMO it is one of least important problems). – 0___________ Jul 21 '20 at 18:12
  • The published standard drafts do not seem to have sections or wordings you quote. – n. m. could be an AI Jul 21 '20 at 18:14
  • 1
    I have dupehammer-reopened the question, as I do not see an answer to the question OP actually asked at https://stackoverflow.com/questions/13950642/why-does-a-function-with-no-parameters-compared-to-the-actual-function-definiti . There is at least arguably an answer at https://stackoverflow.com/questions/41803937/func-vs-funcvoid-in-c99 and/or https://stackoverflow.com/questions/29190986/is-int-main-without-void-valid-and-portable-in-iso-c ; having used the dupehammer to reopen the question, IIRC, I can't re-close it as a duplicate of one of those. – zwol Jul 21 '20 at 18:30
  • @zwol If you want to close with a different one, you'd simply edit the dupe list (add/remove) without re-opening -- that'd avoid the "can't close it again" situation. – P.P Jul 21 '20 at 18:42
  • @P.P. I didn't know editing the dupe list was an option. Where's the UI for that? – zwol Jul 21 '20 at 18:43
  • @zwol This shows the "edit" button: https://meta.stackoverflow.com/a/355667/1275169 – P.P Jul 21 '20 at 18:47
  • @P.P Thanks! I thought that would edit the _question_, not the dupe list. – zwol Jul 21 '20 at 18:48

2 Answers2

3
  1. Per the letter of the standard, yes. 5.1.2.2.1 says "[main] shall be defined with a return type of int[,] and with no parameters, or with two parameters [...]". int main() {} is a definition with return type int and no parameters, and 5.1.2.2.1 does not say anywhere that the definition is required to be prototyped.

    (The code fragment shown immediately after "and with no parameters" may appear to be making a requirement to write (void), but all code fragments are considered to be examples, and therefore non-normative. It doesn't actually say this anywhere in the text, but it has come up in DR responses at least a couple times; I regret I do not remember specific numbers, it was more than 15 years ago now.)

    However, because of (2), you should write int main(void) anyway.

  2. Section 6.5.2.2 (semantics of function calls), paragraph 8, says "the number and types of arguments are not compared with those of the parameters in a function definition that does not include a function prototype declarator." However, paragraph 6 of the same section says that in the event of an actual mismatch between the definition and the callsite the behavior is undefined. That means, compilers are allowed to issue an error when a function defined as T foo() {} is called with arguments, but it also means they are allowed not to issue an error.

    For the sake of backward compatibility with pre-C89 code, which regularly did make function calls with a mismatched number of arguments, many compilers will accept such code without complaint. I have seen this behavior with Clang and MSVC as well as GCC. Newer versions of Clang do give you a warning:

     $ clang --version | head -1
     clang version 9.0.1-13
     $ clang test.c
     test.c:14:14: warning: too many arguments in call to 'bar'
         bar(1, 12);
         ~~~      ^
    

    I don't know how long this warning's been on by default.

    Someone ought to go through all of GCC's intentional leniences for the sake of backward compatibility with really old code, and turn many of them off by default, but nobody's interested in funding this so it probably won't ever happen.

zwol
  • 135,547
  • 38
  • 252
  • 361
  • _Per the letter of the standard, yes_ Even though both `T f() { ... }` and `T f(void) { ... }` define a function with no parameters, these definitions are not 100% equivalent: the first form doesn't provide function prototype. Why you are sure that that _"or equivalent"_ in the C Standard wording about `main` function ignores this difference??? – Language Lawyer Jul 21 '20 at 18:11
  • @LanguageLawyer 5.1.2.2.1, quoted in the question, says "[main] shall be defined with a return type of int[,] and with no parameters, or with two parameters [...]". It does not say that the definition is required to be prototyped. In fact, `int main (argc, argv) int argc; char **argv; { ... }` is still allowed as well, as I read the standard. – zwol Jul 21 '20 at 18:23
  • (2) It is not a deviation, I quote relevant parts of the standard in my answer. It is not clear how it influences (1) as you are not supposed to call `main` anyway. – n. m. could be an AI Jul 21 '20 at 18:30
  • Ok, I kinda see your point. The wording is inaccurate, but "with no parameters" doesn't necessarily mean "with empty parameter list". Function with parameter list consisting of sole `void` is also a function with no parameters. – Language Lawyer Jul 21 '20 at 18:30
  • @n.'pronouns'm. _"you are not supposed to call main anyway"_ Unlike in C++, calling `main` is not forbidden in C. – Language Lawyer Jul 21 '20 at 18:31
  • @LanguageLawyer As I read the standard, _both_ `T foo() {}` and `T foo(void) {}` qualify as a definition with no parameters. See 6.7.6.3 paragraphs 10 and 14. – zwol Jul 21 '20 at 18:31
  • _"both `T foo() {}` and `T foo(void) {}` qualify as a definition with no parameters"_ Yes, but they are not equivalent. `int main(void) { /* ... */ }` in the paragraph about the `main` function is present in normative context. – Language Lawyer Jul 21 '20 at 18:35
  • @n.'pronouns'm. On rereading 6.5.2.2/8 I think you're right and I have edited my answer accordingly. – zwol Jul 21 '20 at 18:40
  • @LanguageLawyer You're going to have to be more specific about what you mean, I am not following you at all. – zwol Jul 21 '20 at 18:40
  • The Standard says _"It shall be defined with a return type of int and with no parameters: `int main(void) { ... }`"_. This `int main(void)` is in normative context and not in an Example or Note, so it provides the precise meaning of what does "with no parameters" mean in that paragraph, even though, generally speaking, a function with empty parameter list is also a function with no parameters. – Language Lawyer Jul 21 '20 at 18:46
  • @LanguageLawyer All code fragments are considered to be examples, even if the word EXAMPLE does not appear in the parent paragraph. This isn't stated in the text anywhere but was critical to the resolution of at least one DR back in the early 2000s. I regret I no longer remember the number. – zwol Jul 21 '20 at 18:51
  • @LanguageLawyer You can. It doesn't mean you should. – n. m. could be an AI Jul 21 '20 at 18:55
3
  1. This standard is vague on this. It does not really define what "or equivalent" means. However you may want to know that the standard uses int main() in at least one code example. Code examples are not normative though.

  2. The call site doesn't see a definition. It only sees a declaration. The (draft document N2176) standard says

    [6.9.1/7] If the declarator includes a parameter type list, the list also specifies the types of all the parameters; such a declarator also serves as a function prototype for later calls to the same function in the same translation unit.

    A declarator without a parameter type list does not serve as a function prototype for later calls, even if it is a part of a definition.

    [6.5.2.2/8] the number and types of arguments are not compared with those of the parameters in a function definition that does not include a function prototype declarator.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • Whether or not an ability to properly process example programs would be required for conformance, I think it's clear that the authors of the Standard would intend that quality implementations should be able to process their sample code meaningfully absent a good reason why they cannot. Further, the Standard's requirements for conformance are so loose as to render the distinction between "normative" and "non-normative" sections essentially meaningless. – supercat Jul 21 '20 at 21:19