C 原型范围

2024-01-18

我了解到

声明的类型说明符 参数列表中的标识符 函数原型中的声明 (不是函数定义的一部分), 标识符具有函数原型 范围,终止于 函数声明符。

请参阅下面提到的C 程序。

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

struct st obj ;

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

我相信原型有这个限制,因为我们也可以在原型声明中使用一些变量名。这些名称可能与同一作用域(如函数原型)中的变量冲突。就像下面这样。

void fn (int a) ;
int a ;

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

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


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

考虑一个内存设置函数:

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++ 编译器和平台允许它?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C 原型范围 的相关文章

随机推荐

  • Django 模型主键作为一对

    我正在尝试制作一个应用程序 用户可以登录他们的个人资料并将歌曲添加到他们最喜欢的列表中 我为此定义了 M2M 关系 我的问题是如何说 歌曲 歌手 的组合是独特的 我搜索了一下 发现通过unique together也许可以 这是设置的正确方
  • 使用 LEFT JOIN 删除

    我想根据引用第一个表的另一个表中存在的数据从表中删除 但是 当我将其作为 SELECT stetement 运行时 我有有效的代码并显示要删除的值 但是当我将其更改为删除它给了我错误 我不明白它们为什么在那里 DELETE leadCust
  • 如何使用facet_wrap在每个方面具有不同数字的离散类别之间创建相等的距离

    我的目标是使图中所有国家之间的距离大致相等 例如 在第一类中 Increase 国家分散 另一方面 第二类和第三类国家彼此距离太近 这迫使我减小国家文本的大小 例如 IS UK 和绘制的估计值 例如 1 5 1 2 因此 一旦我将此文件提取
  • GCE Kubernetes 会话持久化

    我正在 GCE Kubernetes 上运行一个 wordpress woocommerce 网站 但由于会话持久性而在扩展时遇到问题 LoadBalancer GCE Ingress 将所有流量发送到反向代理 然后反向代理将流量发送到我设
  • 在 Scala 中将列表[Try[A]] 转换为列表[A]

    我想从输入数据中过滤掉错误的输入 我目前正在使用scala util Try包装任何异常 下面是一个简单的例子 其中 3I 抛出一个NumberFormatException 我想知道在 Scala 中是否有更好的方法来做到这一点 val
  • OpenGL 和 QtQuick 纹理问题

    我正在基于 Qt 附带的 openglunderqml 示例在 C 中开发一个简单的 QQuickItem 实现 我做了一些修改以使用不同的着色器和加载的两个纹理 这个想法是着色器将在两个纹理之间交叉淡入淡出 本质上只是我加载到纹理中的图像
  • Flutter Web:堆栈和耀斑问题

    我试图在 Flutter Web 开发频道 v1 13 2 上创建一个简单的网页 但出现了这个奇怪的问题 当我尝试在堆栈小部件中放置耀斑动画时 该堆栈小部件分别有 2 个附加小部件 一个背景和一个居中文本 耀斑似乎没有出现 但是当我移除背景
  • 如何将 8 个打包的 32 位整数(在 __m256i 中)的 +-1 符号打包为 64 位整数的字节?

    给定一个 m256i打包 32 位有符号整数的价值 如何获取每个字节所在的单个 64 位数字1如果原始的相应 32 位有符号整数 m256i大于或等于0 并得到 1如果该 32 位整数是负数 AVX2 可能还有 AVX512 很有趣 这是另
  • Jenkins 要求接受 TFS EULA

    我在 Jenkins 上创建了一个附加到 TFS 服务器的构建作业 我使用 Team Explorer Everywhere 来促进这一点 我第一次运行该作业时 收到以下消息 Error You must accept the End Us
  • 如何使用 Express.js 指定 HTTP 错误代码?

    我努力了 app get function req res next var e new Error error message e status 400 next e and app get function req res next r
  • FIND_IN_SET 有两个字符串

    我有这个员工列表的员工表 ID EMPLOYEE ID SKILLS 1 1 3 4 2 2 3 5 2 3 3 1 5 和列
  • ARC Welder 打包的 Android 应用程序只能在 Chrome 操作系统上使用吗?

    如果我使用 Google ARC Welder 打包 Android 应用程序并通过 Chrome 网上应用店分发它 它是否适用于 Windows Mac Linux 还是仅适用于 Chrome 操作系统 如果是这样 有什么消息表明这种情况
  • 使用 openssl C 进行 AES(aes-cbc-128、aes-cbc-192、aes-cbc-256)加密/解密

    我只想用这 3 种模式测试 openSSL 的 AES 密钥长度为 128 192 和 256 但我的解密文本与我的输入不同 我不知道为什么 另外 当我传递一个巨大的输入长度 比方说 1024 字节 时 我的程序显示core dumped
  • 如何在张量流中实现多元线性随机梯度下降算法?

    我从单变量线性梯度下降的简单实现开始 但不知道将其扩展到多元随机梯度下降算法 单变量线性回归 import tensorflow as tf import numpy as np create random data x data np r
  • 我什么时候应该在 scanf() 中使用 & 符号

    在c中使用 符号时使用的规则是什么scanf struct Student char name 20 int id int main void struct Student std1 printf enter name and id of
  • 查看 Azure KeyVault 中 Secret 的内容

    这似乎是一个非常基本的问题 但我在 Azure 中创建了一个 KeyVault 并向其中添加了两个 Secret 它们是使用以下方法保护的纯文本 hello world 示例ConvertTo SecureString Using Get
  • gdb 'x' 命令有什么作用?

    在我寻求更多地了解计算机的一般知识时 我偶然发现了一本书 其中有一些关于反汇编 x86 汇编语言以及 C 和 x86 汇编之间的关系的章节 现在我一直在读这个GDB命令 但我无法完全理解它 该命令及其结果如下 gdb x 32xw esp
  • 分类:类内数据倾斜

    我正在尝试构建一个多标签分类器来预测某些输入数据为 0 或 1 的概率 我正在使用神经网络和 Tensorflow Keras 稍后可能是 CNN 问题如下 数据存在很大偏差 负面例子比正面例子多得多 大概是90 10 所以我的神经网络几乎
  • 使用 swift Codable 从 JSON 数组中提取数据

    我有一个像这样的 JSON 响应 我目前设计的可解码结构如下 struct PortfolioResponseModel Decodable var dataset Dataset struct Dataset Decodable var
  • C 原型范围

    我了解到 声明的类型说明符 参数列表中的标识符 函数原型中的声明 不是函数定义的一部分 标识符具有函数原型 范围 终止于 函数声明符 请参阅下面提到的C 程序 void fn struct st int a a struct st b st