好的,关于这个问题我听到了不同的意见,我只是想确认一下我的理解是否正确.

对于C++

声明void f();void f(void);的意思完全相同,函数f不接受任何参数.定义同上.

对于C

声明void f(void);表示f不接受任何参数.

声明void f();意味着函数f可能有参数,也可能没有参数,如果有,我们不知道这些参数是什么类型的,或者有多少个参数.请注意,它与省略号不同,我们不能使用va_list.

这就是事情变得有趣的地方.

case 1

宣言:

void f();

定义:

void f(int a, int b, float c)
{
   //...
}

case 2

宣言:

void f();

定义:

void f()
{
   //...
}

问题:

在 case 1和 case 2中,当我们使用正确的参数、错误的参数和完全没有参数调用f时,在编译时会发生什么?运行时会发生什么?

补充问题:

如果我用参数声明f,但没有参数定义它,这会有区别吗?我应该能够处理函数体中的参数吗?

推荐答案

更多术语(C,而不是C++):函数的原型声明其参数的类型.否则,该函数没有原型.

void f();                      // Declaration, but not a prototype
void f(void);                  // Declaration and prototype
void f(int a, int b, float c); // Declaration and prototype

不是原型的声明是从K&;R C时代的ANSI C之前遗留下来的.使用旧式声明的唯一原因是为了保持与旧代码的二进制兼容性.例如,在GTK2中,有一个没有原型的函数声明--它意外地出现在那里,但是如果不 destruct 二进制文件就无法删除它.C99标准注释:

6.11.6函数声明符

使用带有空括号的函数声明符(不是原型格式参数

我建议用GCC/Clang编译所有的C代码,除了通常的-Wall -Wextra外,还要用-Wstrict-prototypes-Wmissing-prototypes.

会发生什么

void f(); // declaration
void f(int a, int b, float c) { } // ERROR

声明与函数体不一致!这实际上是一个compile time错误,这是因为在没有原型的情况下,函数中不能有float个参数.不能在非原型化函数中使用float的原因是,当您调用这样的函数时,所有参数都会使用某些默认提升来提升.下面是一个固定的示例:

void f();

void g()
{
    char a;
    int b;
    float c;
    f(a, b, c);
}

在这个程序中,a提升到int1c提升到double.所以f()的定义必须是:

void f(int a, int b, double c)
{
    ...
}

参见C99 6.7.6第15段,

如果一种类型具有参数类型列表,而另一种类型由

答案1

在 case 1和 case 2中,当我们使用正确的参数、错误的参数和完全没有参数调用f时,在编译时会发生什么?运行时会发生什么?

当您调用f()时,参数将使用默认的升级方式升级.如果升级的类型与f()的实际参数类型匹配,则一切正常.如果它们不匹配,它将被编译,但你肯定会得到未定义的行为.

"未定义的行为"指的是"我们不保证会发生什么."也许你的程序会崩溃,也许它会工作得很好,也许它会邀请你的姻亲共进晚餐.

有两种方法可以在编译时获取诊断信息.如果您有一个具有跨模块静态分析功能的复杂编译器,那么您可能会收到一条错误消息.您还可以使用GCC获取非原型函数声明的消息,使用-Wstrict-prototypes——我建议在所有项目中启用-Wstrict-prototypes(使用GTK 2的文件除外).

回答2

如果我用参数声明f,但不带参数定义它,会有什么不同吗?我应该能够处理函数体中的参数吗?

它不应该编译.

例外情况

实际上有两种情况允许函数参数与函数定义不一致.

  1. 可以将char *传递给预期为void *的函数,反之亦然.

  2. 可以将带符号整数类型传递给需要该类型的无符号版本的函数,反之亦然,只要值在这两种类型中都可表示(即,它不是负数,并且没有超出带符号类型的范围).

脚注

1:char提升到unsigned intpossible,但这很少见.

C++相关问答推荐

在x86汇编中,为什么当分子来自RDRAND时DIV会引发异常?

C中是否有语法可以直接初始化一个常量文本常量数组的 struct 成员?

Malloc(sizeof(char[Length]))是否不正确?

当多个线程在C中写入相同的文件描述符时,如何防止争用情况?

平均程序编译,但结果不好

为什么我的Hello World EFI程序构建不正确?

如何按顺序将所有CSV文件数据读入 struct 数组?

通过描述符查找文件路径时出现问题

获取前2个连续1比特的索引的有效方法

条件跳转或移动取决于未初始化值(S)/未初始化值由堆分配创建(Realloc)

如何逐位读取二进制文件?

共享目标代码似乎不能在Linux上的进程之间共享

在C中打印指针本身

在我的第一个C语言中观察到的错误';你好世界';程序

计算时出现奇怪的计算错误;N Select K;在C中

使用 strtok 多次分割一个字符串会导致意外行为

C 错误:对 int 数组使用 typedef 时出现不兼容的指针类型问题

无法理解 fgets 输出

Clang 是否为内联汇编生成了错误的代码?

如何确保 gcc + libc 对于多字节字符串使用 UTF-8,对于 wchar_t 使用 UTF-32?