Func () vs func (void) in c99

void func() In practice, an empty parameter means that any argument is accepted.

void func(void) takes no arguments.

But in the C99 standard, I find lines like this:

6.7.5.3 Declaration of functions (including prototypes)
14 The identifier list only declares function parameter identifiers. An empty list in a function declaration, which is part of the definition of this function, indicates that the function has no parameters. An empty list in the function declarator, which is not part of the definition of this function, indicates that information about the number or types of parameters is not specified.

according to the standard, do func() and func(void) match?

+55
c c99
Jan 23 '17 at 10:18
source share
4 answers

TL; DR

In ads

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

the behavior is completely different. The first declares a function without any prototype - and any number of arguments may be required! While the latter declares a function with a prototype, which has no parameters and takes no arguments.

In the definitions

 void func1() { } // obsolescent 

and

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

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

These two behave distinctly, while the C compiler should print a diagnostic message when calling a prototyped function with the wrong number of arguments, you do not need to do this when calling a function without a prototype.

Ie, given the above definitions

 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 consistent programs, since they are clearly undefined compared to 6.5.2.2p6 .

In addition, empty parentheses are considered an obsolete feature:

Using function declarators with empty brackets (not prototype parameter type declarators) is an obsolete function.

and

Using function definitions with separate parameter identifiers and declaration lists (rather than the type and type of the prototype identifier) ​​is an obsolete function.

More details

There are 2 interrelated but different concepts: parameters and arguments.

  • arguments are the values ​​passed to the function.

  • parameters are names / variables inside the function that are given by the values ​​of the arguments when entering the function

In the following passage:

 int foo(int n, char c) { ... } ... foo(42, ch); 

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

The above excerpt applies only to function parameters, but does not say anything about the prototype or function arguments.




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

The quote in your question means that in the definition of the function , void func1() and void func2(void) both signal to them that there are no parameters, that is, the names of the variables that are set to the values ​​of the arguments when the function is introduced. void func() {} contrasts with void func(); , the first of them states that func does not really accept any parameters, while the latter is an declaration for the func function, for which neither parameters nor their types are specified (declaration without prototype).

However, they do differ by definition in that

  • The definition of void func1() {} does not declare a prototype, whereas void func2(void) {} does because () not a list of parameter types, whereas (void) is a list of parameter types ( 6.7.5.3.10 ):

    A special case of an unnamed parameter of type void as the only element in the list indicates that the function has no parameters.

    and further 6.9.1.7

    If the declarator contains a list of parameter types, list also defines the types of all parameters; such a declarator also serves as a prototype of the function for subsequent calls to the same function in the same translation system. If the declarator contains a list of identifiers, parameter types must be declared in the following declaration list. In any case, the type of each parameter is configured as described in 6.7.5.3 for the list of parameter types; the resulting type must be an object type.

    The function definition declaration for func1 does not contain a list of parameter types , and therefore the function does not have a prototype.

  • void func1() { ... } can still be called with any number of arguments, while a compile-time error causes void func2(void) { ... } with any arguments (6.5.2.2):

    If the expression that denotes the called function is of a type that includes the prototype , the number of arguments must match the number of parameters. Each argument must be of a type so that its value can be assigned to an object with an unqualified version of the type of its corresponding parameter.

    (emphasis mine)

    This is a limitation that, according to the standard, indicates that the corresponding implementation should display at least one diagnostic message about this problem. But since func1 does not have a prototype, an appropriate implementation is not required for any diagnosis.




However, if the number of arguments is not equal to the number of parameters, the behavior is undefined 6.5.2.2p6 :

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

Therefore, the theoretically compatible C99 compiler also makes an error or warning diagnosis in this case. Using StoryTeller provides evidence that clang can diagnose this ; however, my GCC does not seem to do this (and this might also require compatibility with some old obscure code):

 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 by the parameters of the function whose declaration in the definition is not prototyped ( test ), while GCC considers it a compilation error to indicate any arguments to the prototyped function ( test2 ); any appropriate implementation should diagnose this because it is a violation of the constraint.

+52
Jan 23 '17 at 11:49 on
source share
— -

A significant portion of the quote is shown in bold below:

6.7.5.3 Declaration of functions (including prototypes) 14 The list of identifiers declares only identifiers of function parameters. An empty list in a function declaration, which is part of the definition of this function, indicates that the function has no parameters. An empty list in a function declaration that is not part of the definition of this function indicates that information about the number or types of parameters is not specified.

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

 void function1(); // No information about arguments void function2(void); // Function with zero arguments void function3() { // Zero arguments } void function4(void) { // Zero arguments } 
+21
Jan 23 '17 at 10:26
source share

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

No. func(void) says the function takes no arguments at all; whereas func() says that the function takes an indefinite number of arguments. Both are valid, but the func() style is deprecated and should not be used.

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

6.11.6 Function declaration :

Using function declarators with empty brackets (not prototype parameter type declarators) is an obsolete function.

As in the case of C11, it is still obsolete and is not removed from the standard.

+8
Jan 23 '17 at 10:27
source share

An empty list of parameters inside the function definition means that it does not contain a prototype and does not have any parameters.

C11 §6.9.1 / 7 Definitions of functions (emphasis in my current quotes)

A declaration in a function definition indicates the name of the function being defined and its parameter identifiers. If declarator contains a list of parameter types , the list also indicates the types of all parameters; such a declarator also serves as a function prototype for subsequent calls to the same function in the same translation unit.

The question asks:

according to the standard, do func() and func(void) match?

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

C11 §6.5.2.2 / 2 Functional calls (in the restrictions section):

If the expression denoting the called function is of a type that includes the prototype , the number of arguments must match the number of parameters . Each argument must be of a type such that its value can be assigned to the object with an unqualified version the type of the corresponding parameter.

Note that the parameters are ≠ arguments. A function cannot contain any parameters, but may have several arguments.

Since a function defined with empty parameters does not introduce a prototype, it is not checked for its calls, so theoretically it can be supplied with any number of arguments.

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

C11 §6.5.2.2 / 6 Functional calls (in the semantics section):

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

Consequently, the difference is subtle:

  • When a function is defined using void , it will not compile when the number of arguments does not match the parameters (together with their types) due to a violation of constaint (§6.5.2.2 / 2). This situation requires a diagnostic message from the appropriate compiler.
  • If it is specified with empty parameters, it may or may not compile (there is no requirement for a diagnostic message from the corresponding compiler), however, UB calls such a 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 the optimizing compiler may disable arguments in this case. For example, in this way Clang compiles the above code (excluding the func1 call) using -01 on x86-64 in accordance with 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 
+5
Jan 23 '17 at 10:59 on
source share



All Articles