为什么 sizeof (my_arr)[0]编译和等于 sizeof (my_arr [0]) ?

为什么要编译这些代码?

_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, "");

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

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

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

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

Error: unary’*’的无效类型参数(have‘ long unsignedint’) _ Static _ asserit (* sizeof (my _ arr) = = 4,“”) ;

如果需要的话,我使用的是 gcc5.3.0

6843 次浏览

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

这里 是一个到优先级表的链接。

sizeof不是一个函数,而是像 !~那样的一元运算符。

sizeof(my_arr)[0]解析为 sizeof (my_arr)[0],它只是带有冗余括号的 sizeof my_arr[0]

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

一般来说,后缀操作符的优先级高于 C。 sizeof *a[i]++解析中的前缀操作符(后缀操作符 []++首先应用于 a,然后是前缀操作符 *sizeof)。

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

您使用的是以表达式作为参数的 sizeof操作符的版本。与接受类型的函数不同,没有需要括号。因此,操作数只是 (my_arr)[0],括号是多余的。

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])

(顺便说一句,这意味着你之前的 sizeof(my_arr[0])也包含一对多余的 ()。)

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