73

void func()

In practice, an empty parameter means any argument is accepted.

void func(void) accepts no argument.

But in Standard C99, I find such lines:

6.7.5.3 Function declarators (including prototypes)
14 An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. 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.

According to the standard, are func() and func(void) the same?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
liusrichard
  • 733
  • 5
  • 8
  • 2
    I don't know for the standard, but in practice clearly not. – Stargateur Jan 23 '17 at 10:21
  • 1
    It seems clear to me that the standard says that they are different: no information supplied is different from no parameter shall be supplied – Margaret Bloom Jan 23 '17 at 10:22
  • @Margaret,In the bold part, if the declarator is part of a definition it means no parameters – liusrichard Jan 23 '17 at 10:28
  • As a function prototype both `void funct()` and `void func(void)` are different. But when they come as a part of the definition they both are same. `void func() { ... }` and `void func(void) { ... }` both takes no arguments. – haccks Jan 23 '17 at 14:51
  • Possible duplicate of [in c: func(void) vs. func()](https://stackoverflow.com/questions/1163879/in-c-funcvoid-vs-func) – Yousha Aleayoub Mar 14 '18 at 22:12

4 Answers4

77

TL;DR

In declarations,

void func1();     // obsolescent
void func2(void);

the behaviour is quite different. The first one declares a function without any prototype - and it may take any number of arguments! Whereas the latter declares a function with a prototype, that has no parameters and accepts no arguments.

In definitions

void func1() { }     // obsolescent

and

void func2(void) { }
  • The former declares and defines a function func1 that has no parameters and no prototype

  • The latter declares and defines a function func2 with a prototype that has no parameters.

These two behave distinctly in that whereas the C compiler must print a diagnostic message when calling a prototyped function with wrong number of arguments, it needn't do so when calling a function without prototype.

I.e, given the definitions above

func1(1, 2, 3); // need not produce a diagnostic message
func2(1, 2, 3); // must always produce a diagnostic message 
                // as it is a constraint violation

However both calls are illegal in strictly-conforming programs as they're explicitly undefined behaviour as per 6.5.2.2p6.

Furthermore, the empty parentheses are considered an obsolescent feature:

The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.

and

The use of function definitions with separate parameter identifier and declaration lists (not prototype-format parameter type and identifier declarators) is an obsolescent feature.

In detail

There are 2 related, yet distinct concepts: parameters and arguments.

  • arguments are the values passed into the function.

  • parameters are the names/variables within the function that are set to the values of the arguments when the function entered

In the following excerpt:

int foo(int n, char c) {
    ...
}

...

    foo(42, ch);

n and c are parameters. 42 and ch are arguments.

The quoted excerpt only concerns the parameters of a function, but doesn't mention anything about the prototype or arguments to the function.


The declaration void func1() means that the function func1 can be called with any number of arguments, i.e. no information about the number of arguments is specified (as a separate declaration, C99 specifies this as "function with no parameter specification), whereas the declaration void func2(void) means that the function func2 does not accept any arguments at all.

The quote in your question means that within a function definition, void func1() and void func2(void) both signal them that there are no parameters, i.e. variable names that are set to the values of the arguments when the function is entered. The void func() {} contrasts with void func(); the former declares that func indeed takes no parameters, whereas the latter is a declaration for a function func for which neither parameters nor their types are specified (a declaration without prototype).

However, they yet differ definition-wise in that

  • The definition void func1() {} doesn't declare a prototype, whereas void func2(void) {} does, because () is not a parameter type list, whereas (void) is a parameter type list (6.7.5.3.10):

    The special case of an unnamed parameter of type void as the only item in the list specifies that the function has no parameters.

    and further 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. If the declarator includes an identifier list, the types of the parameters shall be declared in a following declaration list. In either case, the type of each parameter is adjusted as described in 6.7.5.3 for a parameter type list; the resulting type shall be an object type.

    The declarator of function definition for func1 does not contain a parameter type list, and thus the function then doesn't have a prototype.

  • void func1() { ... } can still be called with any number of arguments, whereas it is a compile-time error to call void func2(void) { ... } with any arguments (6.5.2.2):

    If the expression that denotes the called function has a type that includes a prototype, the number of arguments shall agree with the number of parameters. Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter.

    (emphasis mine)

    This is a constraint, which according of the standard says that a conforming implementation must display at least one diagnostic message about this problem. But since func1 doesn't have a prototype, a conforming implementation is not required to produce any diagnostics.


However, if the number of arguments does not equal the number of parameters, the behaviour is undefined 6.5.2.2p6:

If the expression that denotes the called function has a type that does not include a prototype, [...] If the number of arguments does not equal the number of parameters, the behavior is undefined.

So in theory a conforming C99 compiler is also allowed to error or diagnose a warning in this case. StoryTeller provided evidence that clang might diagnose this; however, my GCC doesn't seem to do it (and this might also be required for it to be compatible with some old obscure code too):

void test() { }

void test2(void) { }

int main(void) {
    test(1, 2);
    test2(1, 2);
}

When the above program is compiled with gcc -std=c99 test.c -Wall -Werror, the output is:

test.c: In function ‘main’:
test.c:7:5: error: too many arguments to function ‘test2’
     test2(1, 2);
     ^~~~~
test.c:3:6: note: declared here
 void test2(void) { }
      ^~~~~

That is, the arguments are not checked at all against the parameters of a function whose declaration in definition is not prototyped (test) whereas GCC considers it as a compile-time error to specify any arguments to a prototyped function (test2); any conforming implementation must diagnose this as it is a constraint violation.

  • 6.9.1.13 has it explicited: "The difference between these two definitions is that the first form acts as a prototype declaration that forces conversion of the arguments of subsequent calls to the function, whereas the second form does not." (The two definitions are about the same function declarder with a parameter list and an identifier list. An empty list _has_ to be an identifier list, and the equivalent parameter list is simply `void`) – TonioElGringo Jan 23 '17 at 13:31
  • I do not find C spec support that a _function definition_ as `void func1() { }` is an _obsolescent feature_. Perhaps you consider _6.11.6 Function declarators_ applies to a _function definition_? – chux - Reinstate Monica Jan 23 '17 at 16:30
  • 1
    Hmmm Your link to _6.11.7 Function definitions_ and its "separate parameter identifier and declaration lists" does not apply to `void func1() { }`. That does apply to `void func3(a,b) int a; int b; { }` – chux - Reinstate Monica Jan 23 '17 at 17:11
  • 1
    Or; there is a function *declarator* in a function definition too, so then 6.11.6 applies – Antti Haapala -- Слава Україні Jan 23 '17 at 17:23
  • 3
    The Standard does not impose any requirements on what an implementation may do if `int foo() {...};` is called as `foo(5);`, but some implementations can and do define such calls as having useful behaviors, especially if the code for the function makes use of inline assembly or other implementation-defined extensions. Regarding such calls as a constraint violation would have prevented such implementations from providing a useful feature. – supercat Jan 23 '17 at 17:54
21

The significant part of the quote is highlighted in bold below:

6.7.5.3 Function declarators (including prototypes) 14 An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. 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.

So, when the parameter list is empty for a function with its body, they are the same. But of it is just a declaration of a function.

void function1(); // No information about arguments
void function2(void); // Function with zero arguments

void function3() {
    // Zero arguments
}

void function4(void) {
    // Zero arguments
}
Pierre Arlaud
  • 4,040
  • 3
  • 28
  • 42
Mats
  • 8,528
  • 1
  • 29
  • 35
  • 1
    `function3() {..}` does *not* mean "zero arguments". – P.P Jan 23 '17 at 10:28
  • 4
    @usr what does it mean? – Mats Jan 23 '17 at 10:30
  • 2
    It means it takes an unspecified number of arguments. – P.P Jan 23 '17 at 10:31
  • 5
    @usr - The quoted paragraph says it does mean that in a definition, not a declaration. You can't argue with the standard on this. – StoryTeller - Unslander Monica Jan 23 '17 at 10:31
  • @StoryTeller but in practice, `function3()` can take any arguments. Is there a compiler which is the strictly implementation of c99 – liusrichard Jan 23 '17 at 10:36
  • 3
    @StoryTeller If the *definition* has no parameters, well it has..no parameters ;-) I am not sure if the quoted part is directly relevant to the question though. Even a function defined as `int func() {..}` (with no prototype) can still accept arguments in that case, the definition acts as *declration* too. – P.P Jan 23 '17 at 10:36
  • 1
    @liusanman - [As I linked in another comment](http://coliru.stacked-crooked.com/a/5c066b5e97b59969), in practice clang actually implements this paragraph. – StoryTeller - Unslander Monica Jan 23 '17 at 10:38
  • 2
    @usr - It can't. See the link to what clang has to say. – StoryTeller - Unslander Monica Jan 23 '17 at 10:38
  • @StoryTeller Clang is right to point that out (and that's why it's been marked as obsolete in the standard -- because it's error prone). But that doesn't disprove what I said. Btw, proving something by what a particular compiler does is often not the best way, especially in C and C++. – P.P Jan 23 '17 at 10:43
  • @usr: That's not what the obsolescence is referring to. What's obsolete are non-prototype function declarations, not calling a function with the wrong number of arguments. The latter cannot be obsolete, because it's not even *part* of the standard. In the example, `void function3() {}` contains an obsolete declaration and should be changed to `void function3(void) {}`, but that *means the same thing*. – Kerrek SB Jan 23 '17 at 10:45
  • @usr - I know, hence the comment was to answer that attempted to do it. But it was to illustrate that in practice, a compiler is free to implement that paragraph as Mats explained it. There are no two ways to understand that paragraph, it separates the meaning in a definition from other instances of the function prototype. – StoryTeller - Unslander Monica Jan 23 '17 at 10:46
  • @KerrekSB "non-prototype function declarations, not calling a function with the wrong number of arguments." -- they are not mutually exclusive. If there's a prototype, you can't call with wrong number of arguments in *any* C. – P.P Jan 23 '17 at 10:48
  • @usr: Right, but the other way round is under discussion: Using a non-prototype declaration in a function definition. Which *does* fix the number of parameters (as zero), unlike a declaration that is not a definition (but which is apparently also obsolescent). Remember that definitions are also always declarations. – Kerrek SB Jan 23 '17 at 10:49
  • 4
    @KerrekSB I feel like I am repeating myself. But I'll try once more: If there's no prior declaration then the definition acts as declaration. And if that definition has no parameters then it "takes unspecified (but not infinite) number of arguments". (Btw, If something is defined as int fun() {} it very *obviously* has no parameters - I can see that because I am not blind. But that's not disprove what I said. Perhaps, you can explain me the difference between "parameters" and "arguments"). – P.P Jan 23 '17 at 10:59
  • @usr: parameters are part of a function. Arguments are part of an expression. – Kerrek SB Jan 23 '17 at 11:28
  • 2
    @KerrekSB Now, re-read your comment `...the empty list in function3() "specifies that the function has no parameters"; therefore, it cannot be called with any but zero arguments`to find out the nonsense. – P.P Jan 23 '17 at 11:39
  • 7
    This answer is wrong. They are the same parameterwise, but `()` one doesn't specify a prototype and thus the function 3 doesn't have a prototype - it also doesn't have any *parameters* but the number of arguments, or their types, are not checked. – Antti Haapala -- Слава Україні Jan 23 '17 at 12:15
  • @StoryTeller you're both correct and incorrect in your reading of the standard. C99 does not require that a conforming implementation print any diagnostic message, however calling a function with incorrect number of arguments has undefined behaviour, which is why clang prints a diagnostic message. The standard just doesn't require that the arguments are checked to a function without prototype (such requirement doesn't occur in the constraints section). – Antti Haapala -- Слава Україні Jan 23 '17 at 12:36
  • @AnttiHaapala: Yes, you may be right, the function definition in question does *not* constitute a prototype. Functions with no parameters are thus unique in that they can be defined both with and without declaring a prototype. – Kerrek SB Jan 23 '17 at 12:48
  • @usr: I'm sorry, you're right. I think my confusion came from thinking that the definition always constitutes a prototype, which is not in fact the case. – Kerrek SB Jan 23 '17 at 12:49
  • 1
    This doesn't really answer the question, because what people commonly claim is that *even if it is part of a function*, it still doesn't 'count' as a prototype for the purpose of other callers further down in the same translation unit, and therefore if function4 tried to call function3 with arguments it would not give any warning about this being incorrect. Is there any basis for that in the standard? – Random832 Jan 23 '17 at 14:34
  • @KerrekSB: In some implementations, `void foo() {...}` and `void foo(void) {...}` may for all practical purposes mean the same thing, but other implementations may, *at their leisure*, define the former as having useful behaviors which the latter could not (e.g. they specify that all arguments, including the first, may be accessed starting at `*__caller_sp`, and a called function may as many or as few arguments as it sees fit provided only that it doesn't try to use more than are passed). – supercat Jan 23 '17 at 18:35
  • @supercat: I don't think that's allowed in standard C. The body of `foo` (which is right there) is the body of a function with no parameters (that's what the quote says in this answer), and calling it with any other number of parameters is UB (see the quotes of 6.5.2.2/6 elsewhere here). The lack of a prototype merely means that calling the function with the wrong number of arguments is UB and not ill-formed. (I suppose your implementation could promise particular behaviour under the guise of UB, but that wouldn't be portable.) – Kerrek SB Jan 23 '17 at 18:56
  • @KerrekSB: The fact that it's UB means that implementations may do whatever they like with the construct, *including giving it a useful meaning*. – supercat Jan 23 '17 at 18:58
  • @supercat: OK, sure, that's true. – Kerrek SB Jan 23 '17 at 19:01
  • @KerrekSB: Many implementations did in fact give such a construct a usable meaning, and forbidding it would have prevented implementations from continuing to support it. If, for example, one needed a function which would tail-call to a variadic function if some condition was true, and return otherwise, that might be accomplished easily with the aid of inline assembly or other system-specific means, but only if the compiler-generated code for the called function didn't set up a stack frame. If the variadic function can't be rewritten to accept a va_list, ... – supercat Jan 23 '17 at 19:09
  • ...it may be harder to convince a compiler to generate the necessary code for the wrapper. Such things wouldn't be portable, of course, but that doesn't mean that they wouldn't be useful, nor that outlawing them wouldn't have broken useful code in ways that might be difficult to fix [especially if they liked to object modules whose source was unavailable]. – supercat Jan 23 '17 at 19:11
  • What do you mean by *"But of it is just a declaration of a function"*? It seems partly incomprehensible. Preferably, please respond by [editing your answer](https://stackoverflow.com/posts/41804057/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Nov 12 '21 at 04:01
10

according to the standard, func() and func(void) is the same?

No. func(void) says the function takes no arguments at all; whereas func() says the function takes an unspecified number of arguments. Both are valid but the func() style are obsolete and shouldn't be used.

This is an artifact from pre-standard C. C99 marked this as obsolete.

6.11.6 Function declarators:

The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.

As of C11, it still remains as obsolescent and hasn't been removed from the standard.

P.P
  • 117,907
  • 20
  • 175
  • 238
  • 1
    Hopefully it gets removed in 2x. – 2501 Jan 23 '17 at 10:38
  • but according to [6.7.5](http://port70.net/~nsz/c/c99/n1256.html#6.7.5.3p14), it looks like the same. – liusrichard Jan 23 '17 at 10:41
  • @2501: Before prototypes were added to C, most C compilers for microcomputers used a calling convention which placed arguments at predictable displacements on the stack, and where arguments beyond those the compiler knew about would be harmless. The Standard doesn't require such semantics because not all platforms can support it, but because on some platforms it allows semantics that could not be achieved as effectively via other means there should continue to be a standard-recognized means via which platforms which offer such semantics could continue to do so. That wouldn't mean... – supercat Jan 23 '17 at 21:06
  • ...that compilers which don't offer such semantics would be under obligation to accept the syntax--merely that there be *some* standard syntax which implementations could support or not at their leisure to indicate the old semantics. Having a new syntax could actually facilitate migration of code that relies upon the semantics to new systems if compiler writers who wish to ease such migration use the syntax to emulate the old calling convention. – supercat Jan 23 '17 at 21:10
6

The empty parameter list inside a function definition means that it does not include a prototype nor has any parameters.

C11 §6.9.1/7 Function definitions (emphasis in ongoing quotes is mine)

The declarator in a function definition specifies the name of the function being defined and the identifiers of its parameters. 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.

The question asks:

according to the standard, func() and func(void) is the same?

No. The essential difference between void func() and void func(void) lies in their calls.

C11 §6.5.2.2/2 Function calls (within constraints section):

If the expression that denotes the called function has a type that includes a prototype, the number of arguments shall agree with the number of parameters. Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter.

Notice that parameters ≠ arguments. The function may contain no parameters, but it may have multiple arguments.

As a function defined with empty parameters does not introduce a prototype, it's not checked against its calls, so in theory it may be supplied with whatever number of arguments.

However, it is technically an undefined behavior (UB) to call such function with at least one argument (see Antti Haapala's comments).

C11 §6.5.2.2/6 Function calls (within semantics section):

If the number of arguments does not equal the number of parameters, the behavior is undefined.

Hence, the difference is subtle:

  • When a function is defined with void, it won't compile when number of arguments don't match with parameters (along with their types), because of constraint violation (§6.5.2.2/2). Such a situation requires diagnostic message from a conforming compiler.
  • If it is defined with empty parameters, it may or may not compile (there is no requirement for a diagnostic message from a conforming compiler), however it's UB to call such function.

Example:

#include <stdio.h>

void func1(void) { puts("foo"); }
void func2()     { puts("foo"); }

int main(void)
{
    func1(1, 2); // constraint violation, it shouldn't compile
      func2(3, 4); // may or may not compile, UB when called
    return 0;
}

Note that an optimizing compiler may cut off the arguments in such a case. For instance, this is how Clang compiles the above code (excluding func1's call) with -01 on x86-64 according to the SysV ABI calling conventions:

main:                                   # @main
        push    rax          ; align stack to the 16-byte boundary
        call    func2        ; call func2 (no arguments given)
        xor     eax, eax     ; set zero as return value
        pop     rcx          ; restore previous stack position (RSP)
        ret
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137