在确定数组的大小时,括号会有所不同吗?
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
运算符或一元&
运算符的操作数,或者是用于初始化字符类型数组的字符串文字,或者是用于初始化数组的宽字符串文字与wchar_t
兼容的元素类型,具有“类型数组”类型的左值将转换为具有“类型指针”类型的表达式,该类型指向数组对象的初始成员并且不是左值。
为了清楚起见,他认为 (a)
应该触发数组到指针的衰减,因为上面的列表中没有包含括号(sizeof
运算符,一元 &
运算符,字符串文字作为初始化器)。
【问题讨论】:
不,那家伙很糊涂 用他自己的话说,我同意终端困惑 我已经有 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
的类型与&*argv
不同。
我发现LENGTHOF(a)
不太吸引人,因为字符串的长度和相应字节数组的大小之间可能存在混淆。我同意这些工具就足够了,例如:typeof(a) != typeof(&*(a))
@chqrlie see this thread 讨论这样一个宏
@chqrlie 你可能也对this question感兴趣。【参考方案2】:
从 C99, 6.5.1 开始,括号内的表达式:
它的类型和值与不带括号的表达式相同。
乍一看,这似乎与您所指的例外列表(6.3.2.1)冲突:
除非它是
sizeof
运算符或一元&
运算符的操作数,或者是用于初始化数组的字符串文字,否则类型为“类型数组”的表达式将转换为具有键入“类型指针”...
但是,此列表是在运算符/操作数的上下文中;括号似乎不被视为运算符(基于第 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核心技术(卷一)读后的思考(泛型数组列表的讨论)