c99中的func()vs func(void)

时间:2017-01-23 10:18:56

标签: c c99

void func() 实际上,空参数表示接受任何参数。

void func(void)不接受任何争论。

但在标准C99中,我找到了这样的界限:

  

6.7.5.3 Function declarators (including prototypes)
  14标识符列表仅声明函数参数的标识符。 函数声明符中的空列表是该函数定义的一部分,指定该函数没有参数。函数声明符中不属于该函数定义的空列表指定没有提供有关参数数量或类型的信息。

根据标准,func()func(void)是一样的吗?

3 个答案:

答案 0 :(得分:21)

引用的重要部分在下面以粗体突出显示:

  

6.7.5.3函数声明符(包括原型)14标识符列表仅声明函数参数的标识符。函数声明符中的空列表该函数的定义的一部分指定该函数没有参数。函数声明符中的空列表不属于该函数的定义,指定不提供有关参数数量或类型的信息。

因此,当参数列表对于具有其主体的函数为空时,它们是相同的。但它只是一个函数的声明。

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

void function3() {
    // Zero arguments
}

void function4(void) {
    // Zero arguments
}

答案 1 :(得分:8)

  

根据标准,func()和func(void)是一样的吗?

没有。 func(void)表示该函数完全采用 no 参数;而func()表示该函数采用了未指定数量的参数。两者都有效,但func()样式已过时,不应使用。

这是来自预标准C的工件.C99将其标记为过时。

6.11.6 Function declarators

  

使用带有空括号的函数声明符(不是prototype-format参数类型声明符)是一个过时的功能。

从C11开始,它仍然是过时的,并且没有从标准中删除。

答案 2 :(得分:5)

函数定义中的空参数列表表示它不包含原型,也没有任何参数。

C11§6.9.1/ 7 功能定义 (强调正在进行的报价是我的)

  

函数定义中的声明符指定了该名称   正在定义的函数及其参数的标识符。 如果   声明器包含一个参数类型列表,该列表也指定了   所有参数的类型; 这样的声明者也可以作为一个   函数原型,以便以后调用同一个函数   翻译单位。

问题是:

  

根据标准,func()func(void)是一样的吗?

没有。 void func()void func(void)之间的本质区别在于他们的电话。

C11§6.5.2.2/ 2 函数调用(在约束部分内):

  

如果表示被调用函数的表达式具有类型   包含原型,参数数量应与之相符   参数数量。每个参数都应具有一个类型   value可以分配给具有非限定版本的对象   其相应参数的类型。

请注意,参数≠参数。该函数可能不包含任何参数,但可能有多个参数。

由于使用空参数定义的函数不会引入原型,因此不会根据其调用进行检查,因此从理论上讲,它可以提供任何数量的参数。

但是,从技术上讲,undefined behavior用至少一个参数来调用这个函数(参见Antti Haapala的comments)。

C11§6.5.2.2/ 6 函数调用(在语义部分内):

  

如果参数的数量不等于参数的数量,   行为未定义。

因此,差异很微妙:

  • 当使用void定义函数时,由于constaint违规(§6.5.2.2/ 2),当参数数量与参数(及其类型)不匹配时,它将不会编译。这种情况需要来自合规编译器的诊断消息。
  • 如果使用空参数定义,可能可能不编译(不需要来自符合编译器的诊断消息),但它是UB到打电话这样的功能。

示例:

#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;
}

请注意optimizing compiler可能会在这种情况下切断参数。例如,这是Clang根据SysV ABI调用约定在x86-64上用func1编译上述代码(不包括-01的调用)的方式:

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