参数名称可以帮助记录参数的使用。
考虑一个内存设置函数:
void mem_set(void *, int, int);
void mem_set(void *buffer, int value, int nbytes);
哪个更容易理解?
所编写的结构类型声明对于函数原型来说是本地的。您可能知道(现在,如果不是以前),您需要在原型范围之外定义类型才能成功使用它。也就是说,你必须写:
struct st {int a;};
void fn(struct st a, struct st b);
You say:
我相信原型有这个限制,因为我们也可以在原型声明中使用一些变量名。这些名称可能与同一作用域(如函数原型)中的变量冲突。就像下面这样。
void fn(int a);
int a;
因此,为了允许上述声明,原型的范围受到限制。 (如果我错了请纠正我)
带有“-Wshadow”的 GCC 有可能会警告参数“a”遮蔽全局变量“a”——它肯定会在函数定义中这样做,并且可能在函数声明中这样做。但这不是强制性警告;编写的代码是合法的 C - 尽管由于阴影而有点可疑。
评论中有一个旷日持久的讨论“为什么 C 限制(阻止)你在参数列表中声明类型”,副文本是“因为 C++ 确实允许你这样做”:
Comments
允许使用 /**/ ,程序员有责任(根据编码实践)添加有关该语言使用的适当注释。我相信除了为评论提供帮助之外还必须有“其他东西”。 – 加内什·戈帕拉苏布拉曼尼安
好吧——相信吧。其余原因是与 C++ 的兼容性,并且添加了参数名称以提高可读性。请参阅 Stroustrup“C++ 的设计和演变”。请注意,原型中的参数名称不是接口的一部分 - 请参阅有关按名称而不是位置提供参数的讨论。 ——乔纳森·莱夫勒
我相信OP提出的问题是“拥有函数原型范围有什么意义?”。不幸的是,你的回答并没有阐明这一点。坦白说,我也不知道。如果他们只是想像 OP 猜测的那样限制命名参数声明的范围(在非定义声明中),他们可以在不引入范围的情况下完成它(例如,就像在 C++ 中所做的那样)。 – 安德烈·T
@AndreyT:在函数定义中,参数是函数体的本地参数(不再可能通过函数体最外层块中的局部变量隐藏参数)。原型在逻辑上声明了函数内部的类型,因此应该按定义的范围进行定义 - 因此,仅在函数原型中定义的类型不能在函数外部使用,并且无法调用的函数对任何人都没有什么好处。 ——乔纳森·莱夫勒
@Jonathan Leffler:您似乎在解释为什么允许参数名称(“与 C++ 的兼容性”- 好的)。我想知道的是引入“函数原型作用域”的理由。为什么他们认为有必要引入这样一个范围? C++ 不这样做。 C++ 中没有函数原型作用域。 – 安德烈·T
@AndreyT 是啊!我们都在同一条船上溺水:) – Ganesh Gopal Subramaniam
反例
这表明 C++“确实是这样做的”。
#include <cstdio>
using namespace std;
extern void x(struct c {int y;} b);
void x(struct c b)
{
printf("b.y = %d\n", b.y);
}
int main()
{
struct c a;
a.y = 0;
x(a);
return(0);
}
此代码无法使用 G++(MacOS X 10.5.8 上的 4.0.1)进行编译。它抱怨:
$ g++ -o xx xx.cpp
xx.cpp:4: error: types may not be defined in parameter types
$
该错误发生在默认的警告/错误级别以及迂腐的级别。
因此,在这种情况下说“C 的行为与 C++ 的行为相同”似乎是公平且准确的。您能否用反反示例演示如何在 C++ 函数原型中定义类型,并指定哪个 C++ 编译器和平台允许它?