C 原型(prototype)范围

标签 c prototype scope designer specifications

我知道了

the type specifier that declares the identifier in the list of parameter declarations in a function prototype (not part of a function definition), the identifier has function prototype scope, which terminates at the end of the function declarator.

请看下面提到的C程序。

void fn (struct st {int a;} a, struct st b) ;

struct st obj ;

编译器会立即发出错误,因为“obj”大小未知(或)struct st 不是“类型”。这是正确的!结构“struct st”的声明在原型(prototype)声明处结束。

我相信原型(prototype)有这个限制,因为我们也可以在原型(prototype)声明中使用一些变量名。这些名称可能与同一范围内的变量(如函数原型(prototype)的范围)冲突。如下所示。

void fn (int a) ;
int a ;

因此,为了允许上述声明,原型(prototype)的范围是有限的。 (如果我错了请纠正我)

但是,对于原型(prototype)声明,参数变量名是没有用的。那么,为什么它被“缩小范围”?参数变量名有什么意义?语言设计者(或)规范对此有何看法?

最佳答案

参数名称可以帮助记录参数的使用。

考虑一个内存设置函数:

void mem_set(void *, int, int);

void mem_set(void *buffer, int value, int nbytes);

哪个更容易理解?


所写的结构类型声明是局部于函数原型(prototype)的。您可能知道(现在,如果不是以前的话),您需要在原型(prototype)范围之外定义类型才能成功使用它。也就是说,你必须写:

struct st {int a;};
void fn(struct st a, struct st b);

你说:

I believe prototype had this limit because we can use some variable names in the prototype declarations too. These names may conflict with the variables in the same scope (as that of function prototype). Like below.

void fn(int a);
int a;

So, to allow the above declarations the scope of prototype is limited. (Correct me if I am wrong)

带有“-Wshadow”的 GCC 可能会警告参数“a”隐藏了全局变量“a”——它肯定会在函数定义中这样做,也可能在函数声明中这样做。但这不是强制性警告;编写的代码是合法的 C - 尽管由于阴影而有点可疑。


关于“为什么 C 限制(阻止)你在参数列表中声明类型”的评论中有一个旷日持久的讨论,潜台词是“因为 C++ 确实允许你这样做”:

评论

Being allowed of /**/, it should be the programmer's responsibility (as per coding practices) to add proper comments about the use of the language there. I believe there has to be 'something' other than providing assistance to comments. – Ganesh Gopalasubramanian

OK - believe away. Compatibility with what C++ did was the rest of the reason, and the argument names were added there to promote readability. See Stroustrup 'Design and Evolution of C++'. Note that the names of the parameters in the prototype are not part of the interface - see the discussion on providing arguments by name instead of position. – Jonathan Leffler

I believe the question the OP is asking is "what's the point of having function prototype scope at all?". You answer, unfortunately, does not shed any light on it. Frankly, I have no idea either. If they simply wanted to limit the scope of named parameter declarations (in a non-defining declaration) as OP guesses, they could've done it without introducing a scope (as it is done in C++ for example). – AndreyT

@AndreyT: in a function definition, the arguments are local to the body of the function (it is no longer possible to hide an argument by a local variable in the outermost block of the body of the function). The prototype logically declares a type inside the function, and therefore should be scoped as defined - and hence, a type defined only in the function prototype cannot be used outside the function, and a function that cannot be called is of little benefit to anyone. – Jonathan Leffler

@Jonathan Leffler: You seem to be explaining why the parameter names were allowed ("compatibility with C++" - OK). What I'd like to know is the rationale for introducing the "function prototype scope". Why did they see the need to introduce such a scope? C++ doesn't do it that way. There's no function prototype scope in C++. – AndreyT

@AndreyT Yeh! We both are drowning in the same boat :) – Ganesh Gopalasubramanian

反例

这表明 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++ 的函数原型(prototype)中定义类型,并指定允许它的 C++ 编译器和平台吗?

关于C 原型(prototype)范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1736560/

相关文章:

c - 当 BSD 套接字报告已收到 RST 时,如果尚未读取所有内容

c - 如何定义枚举增量步骤?

调用约定和语言绑定(bind)

JavaScript:扩充对象/函数原型(prototype)避免名称冲突

javascript - 正则表达式匹配 #{} 中的名称以供模板使用

javascript - 我如何 setInterval 调用类中的函数

c - 为什么这两个相似的递归 C 代码给出不同的输出?

uitableview - iOS Storyboard: set a background color to prototype cell

javascript - 在 Javascript 中将对象转换为上下文

php - 关于 PHP 中的作用域和 OOP