在确定数组的大小时,括号会有所不同吗?

Posted

技术标签:

【中文标题】在确定数组的大小时,括号会有所不同吗?【英文标题】:Do parentheses make a difference when determining the size of an array? 【发布时间】:2015-08-13 23:32:09 【问题描述】:

以下程序在 gcc 4.8.2 上两次打印相同的数字:

#include <stdio.h>

int main()

    char a[13];
    printf("sizeof a  is %zu\n", sizeof a );
    printf("sizeof(a) is %zu\n", sizeof(a));

根据this reddit post,gcc 在这方面不符合标准,因为当数组到指针衰减不发生时,括号中的表达式不在例外列表中。

这个人说的对吗?以下是相关的标准报价:

除非它是 sizeof 运算符或一元 &amp; 运算符的操作数,或者是用于初始化字符类型数组的字符串文字,或者是用于初始化数组的宽字符串文字与wchar_t 兼容的元素类型,具有“类型数组”类型的左值将转换为具有“类型指针”类型的表达式,该类型指向数组对象的初始成员并且不是左值。

为了清楚起见,他认为 (a) 应该触发数组到指针的衰减,因为上面的列表中没有包含括号(sizeof 运算符,一元 &amp; 运算符,字符串文字作为初始化器)。

【问题讨论】:

不,那家伙很糊涂 用他自己的话说,我同意终端困惑 我已经有 15 年没有处理这个问题了,但我绝对记得我认为 sizeof 的一个场景,其中是否存在括号很重要——确定是否您正在获取指针的大小或元素的大小,或类似的东西。 现在我很困惑。该代码的确切目的是什么?你期望从你的 sizeof 表达式中得到什么?数组的长度?但你知道的。一个字符的大小?那为什么不 sizeof (char) 呢?指针的大小,因为数组基本上是指针? @jamesqf 我想知道将数组放入括号是否会触发数组到指针的衰减。 【参考方案1】:

看似多余的括号是否会影响程序的语义是 C 标准中长期存在的问题,但仍未得到充分解决。

通常声称((void*)0) 在技术上不是空指针常量,因为没有规则说带括号的空指针常量是空指针常量。

一些编译器对char s[] = ("abc"); 发出错误,因为虽然可以从字符串文字初始化字符数组,但该规则不包括带括号的字符串文字。

类似的例子还有很多。你找到了其中之一。

据我所知,基本共识是规则应该是 C++ 所做的,但 C 从未正式采用。 C++ 使带括号的表达式在功能上等同于不带括号的表达式,但有一些明确声明的例外。这将一次性涵盖所有这些问题。

所以从技术上讲,这个人可能被认为是正确的,但这是对标准的过于严格的解释,没有人真正遵循,因为众所周知,标准在这里只是有缺陷。

【讨论】:

不能简单地测试一个标识符是指一个指针还是一个数组,这已经够糟糕的了,这使得sizeof(argv) 容易出错。如果 sizeof(argv)sizeof argv 评估为不同的东西,情况会更糟。真正需要的是一个countof(a) 运算符,它计算数组元素的数量,并在应用于非数组时发出编译时错误。 @chqrlie 我宁愿拥有创建countof 所需的构建块(我通常看到它命名为LENGTHOF,但两者都可以)我们自己。使用 C11 的 _Generic,我认为缺少的只是类似于 C++11 的 decltype。如果我们有这个,我们就可以静态验证argv 的类型与&amp;*argv 不同。 我发现LENGTHOF(a) 不太吸引人,因为字符串的长度和相应字节数组的大小之间可能存在混淆。我同意这些工具就足够了,例如:typeof(a) != typeof(&amp;*(a)) @chqrlie see this thread 讨论这样一个宏 @chqrlie 你可能也对this question感兴趣。【参考方案2】:

从 C99, 6.5.1 开始,括号内的表达式:

它的类型和值与不带括号的表达式相同。

乍一看,这似乎与您所指的例外列表(6.3.2.1)冲突:

除非它是 sizeof 运算符或一元 &amp; 运算符的操作数,或者是用于初始化数组的字符串文字,否则类型为“类型数组”的表达式将转换为具有键入“类型指针”...

但是,此列表是在运算符/操作数的上下文中;括号似乎不被视为运算符(基于第 6.5 节结构隐含的分类)。

【讨论】:

您可以直接链接到该部分,这要感谢一些勇敢的灵魂,他们花了很多时间将 pdf 文档转换为 html:iso-9899.info/n1256.html#6.5.1p5、iso-9899.info/n1256.html#6.3.2.1p3 ... 或对于 C11:iso-9899.info/n1570.html#6.5.1p5、@ 987654324@ C11 似乎只允许在带括号的版本 (6.5.3#1) 中使用 type-name。关于这一点,在 unary-expression 周围带有括号的版本在语法上将是未加括号的版本,其中括号是 unary-expression 的一部分。使编译器的工作变得不简单。编辑:C99 相同。

以上是关于在确定数组的大小时,括号会有所不同吗?的主要内容,如果未能解决你的问题,请参考以下文章

关于JAVA核心技术(卷一)读后的思考(泛型数组列表的讨论)

为啥数组会引起nvlink警告:入口函数的堆栈大小不能静态确定

转换为指向运行时确定大小的数组的指针

是否可以在 Rust 运行时确定大小的堆栈分配数组?

确定图像是不是相同,但大小不同

在 C++ 中表示二维数组的最佳方法,其大小在运行时确定