为什么sizeof(my_arr)[0]编译并且sizeof(my_arr [0])?

时间:2017-10-09 19:09:19

标签: c sizeof

为什么这段代码会编译?

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

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

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

4 个答案:

答案 0 :(得分:192)

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])++))(后缀运算符[]++应用于{{1首先,然后是前缀运算符a*)。

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

答案 1 :(得分:44)

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

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

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

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

答案 2 :(得分:24)

[]的优先级高于sizeof。因此sizeof(my_arr)[0]sizeof((my_arr)[0])相同。

Here是指向优先表的链接。

答案 3 :(得分:7)

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