为啥 sizeof(my_arr)[0] 编译并等于 sizeof(my_arr[0])?

Posted

技术标签:

【中文标题】为啥 sizeof(my_arr)[0] 编译并等于 sizeof(my_arr[0])?【英文标题】:Why does sizeof(my_arr)[0] compile and equal sizeof(my_arr[0])?为什么 sizeof(my_arr)[0] 编译并等于 sizeof(my_arr[0])? 【发布时间】:2018-03-21 01:46:18 【问题描述】:

为什么这段代码会编译?

_Static uint32_t my_arr[2];
_Static_assert(sizeof(my_arr) == 8, "");
_Static_assert(sizeof(my_arr[0]) == 4, "");
_Static_assert(sizeof(my_arr)[0] == 4, "");

前 2 个断言显然是正确的,但我预计最后一行会失败,因为我的理解是 sizeof() 应该评估为整数文字,不能将其视为数组。换句话说,它会以与以下行失败相同的方式失败:

_Static_assert(4[0] == 4, "");

有趣的是,以下确实无法编译(应该做同样的事情,不是吗?):

_Static_assert(*sizeof(my_arr) == 4, "");

错误:一元'*'的无效类型参数(有'long unsigned int') _Static_assert(*sizeof(my_arr) == 4, "");

如果重要的话,我使用的是 gcc 5.3.0

【问题讨论】:

我怀疑 ( sizeof( my_arr ) )[ 0 ] 失败了。 最近的一个副本在这个语法上有另一个变化:Why does sizeof(x)++ compile? 【参考方案1】:

sizeof 不是函数。它是一个一元运算符,例如 !~

sizeof(my_arr)[0] 解析为sizeof (my_arr)[0],这只是sizeof my_arr[0] 带有多余的括号。

这就像!(my_arr)[0] 解析为!(my_arr[0])

通常,后缀运算符的优先级高于 C 中的前缀运算符。sizeof *a[i]++ 解析为 sizeof (*((a[i])++))(后缀运算符 []++ 首先应用于 a,然后是前缀运算符 @987654335 @ 和 sizeof)。

(这是sizeof 的表达式版本。还有一个类型版本,它采用带括号的类型名称:sizeof (TYPE)。在这种情况下,括号是必需的,并且是sizeof 语法的一部分。)

【讨论】:

我当然知道 sizeof 是一元运算符而不是函数,但完全忘记了。哎呀。感谢您的详细解释。无论如何,[] 的优先级高于 * 的事实很有趣。 @melpomene 很有趣。我从没想过sizeof 是一元运算符。 你不是说"... parses as sizeof (my_arr[0])"吗?只是添加一个空格并没有真正改变任何东西。 我会推荐sizeof((my_array)[0]) Why is sizeof considered an operator?【参考方案2】:

sizeof 有两个“版本”:sizeof(type name)sizeof expression。前者需要一对 () 围绕它的论点。但后者 - 以表达式作为参数的那个 - 在其参数周围没有()。无论您在参数中使用什么(),都被视为参数表达式的一部分,而不是sizeof 语法本身的一部分。

由于编译器知道my_arr 是对象名称,而不是类型名称,因此编译器实际上将您的sizeof(my_arr)[0] 视为sizeof 应用于表达式:sizeof (my_arr)[0],其中(my_arr)[0] 是参数表达式。数组名称周围的() 完全是多余的。整个表达式被解释为sizeof my_arr[0]。这相当于你之前的sizeof(my_arr[0])

(顺便说一句,这意味着您之前的@​​987654336@ 还包含一对多余的()。)

sizeof 的语法在某种程度上需要一对() 围绕其参数,这是一个相当普遍的误解。在解释sizeof(my_arr)[0]等表达时,这种误解会误导人们的直觉。

【讨论】:

第一个版本的存在是为了让您可以在机器上检查整数的大小(从后面甚至没有 64 位机器!),但 int 不是一个有效的表达式,所以你不能使用第二种形式。【参考方案3】:

[] 的优先级高于sizeof。所以sizeof(my_arr)[0]sizeof((my_arr)[0]) 是一样的。

Here 是指向优先表的链接。

【讨论】:

【参考方案4】:

您正在使用将表达式作为参数的sizeof 运算符版本。与采用类型的不同,它不需要 括号。因此,操作数只是(my_arr)[0],括号是多余的。

【讨论】:

以上是关于为啥 sizeof(my_arr)[0] 编译并等于 sizeof(my_arr[0])?的主要内容,如果未能解决你的问题,请参考以下文章

array

C语言如何求一个二维数组有几行,还有为啥会提示gets()是一个未定义的标识符?

C语言 数组的问题,书上的例子,说a = sizeof(mu) / sizeof(mu[0])可以统计数组的元素个数,为啥?

重新索引数组

从数组中删除空元素

为啥文件扩展名对编译有影响?