c - c99 中的 func() 与 func(void)

标签 c c99

void func()实际上,空参数意味着接受任何参数。
void func(void)不接受任何争论。

但是在标准 C99 中,我发现了这样的几行:

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.



按照标准,func()func(void)是一样的吗?

最佳答案

TL; 博士

在声明中,

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

行为完全不同。第一个声明了一个没有任何原型(prototype)的函数——它可以接受任意数量的参数!而后者声明了一个带有原型(prototype)的函数,它没有参数并且不接受任何参数。

在定义中
void func1() { }     // obsolescent


void func2(void) { }
  • 前者声明并定义了一个函数 func1没有参数和 没有原型(prototype)
  • 后者声明并定义了一个函数 func2 带有原型(prototype) 没有参数。

  • 这两者的行为截然不同,因为 C 编译器在调用带有错误数量参数的原型(prototype)函数时必须打印诊断消息,它 不需要在调用没有原型(prototype)的函数时这样做。

    即,鉴于上述定义
    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
    

    然而,这两个调用在严格遵守的程序中都是非法的,因为根据 6.5.2.2p6,它们是明确未定义的行为。 .

    此外,空括号被认为是一个过时的特征:

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





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



    详细

    有两个相关但不同的概念:参数和参数。
  • 参数是传递给函数的值。
  • 参数是函数内的名称/变量,当函数进入时设置为参数的值

  • 在以下摘录中:
    int foo(int n, char c) {
        ...
    }
    
    ...
    
        foo(42, ch);
    
    nc是参数。 42ch是论据。

    引用的摘录只涉及函数的参数,但没有提及函数的原型(prototype)或参数。

    声明void func1()表示函数 func1可以用 调用任意数量的参数 ,即没有指定关于参数数量的信息(作为单独的声明,C99 将其指定为“没有参数指定的函数),而声明 void func2(void) 意味着函数 func2 根本不接受任何参数。

    您问题中的引用意味着在 内函数定义 , void func1()void func2(void)两者都向他们发出信号,表示没有参数,即在输入函数时设置为参数值的变量名称。 void func() {}对比void func();前者声明 func确实没有参数,而后者是函数的声明 func既没有指定参数也没有指定它们的类型(没有原型(prototype)的声明)。

    然而,它们在定义上有所不同,因为
  • 定义void func1() {}不声明原型(prototype),而 void func2(void) {}确实如此,因为 ()不是参数类型列表,而 (void)是参数类型列表( 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.



    以及 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.


    func1 的函数定义声明符不包含 参数类型列表 ,因此该函数没有原型(prototype)。
  • void func1() { ... }仍然可以使用任意数量的参数调用,而调用 void func2(void) { ... } 是编译时错误。带有任何参数(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.



    (强调我的)

    这是一个 约束 ,根据标准,这是一个符合标准的实现 必须至少显示一条有关此问题的诊断消息。但由于 func1没有原型(prototype),生成任何诊断不需要符合要求的实现。


  • 但是,如果参数数量不等于参数数量,则 行为未定义 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.



    因此,理论上,在这种情况下,也允许符合 C99 的编译器出错或诊断警告。 StoryTeller提供证据表明clang might diagnose this ;但是,我的 GCC 似乎没有这样做(这也可能需要它与一些旧的晦涩代码兼容):
    void test() { }
    
    void test2(void) { }
    
    int main(void) {
        test(1, 2);
        test2(1, 2);
    }
    

    当上面的程序用gcc -std=c99 test.c -Wall -Werror编译时,输出为:
    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) { }
          ^~~~~
    

    也就是说,对于定义中的声明不是原型(prototype)的函数的参数(test),根本不会检查参数,而 GCC 认为将任何参数指定给原型(prototype)函数(test2)是编译时错误。 );任何符合要求的实现都必须对此进行诊断,因为它违反了约束。

    关于c - c99 中的 func() 与 func(void),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41803937/

    相关文章:

    c - 如果变体具有 INF 或 NAN 值,如何使变体的 ChangeType float ?

    C : how can I change from file descriptor to FILE struct and vice versa?

    C和 Bison : pointers to struct in %union definition

    c - C99 中的声明符语义

    带有结构指针的 C 结构

    c - 海湾合作委员会警告 : pointer arithmetic with type void *

    将默认值从 Extern 更改为 Static

    c - C99 宏中的循环构造

    c - sizeof() 具有零长度数组成员的结构

    c99 中 float 的编译时间/宏交换