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

Why does sizeof(my_arr)[0] compile and equal 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, "");

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

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

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

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

error: invalid type argument of unary '*' (have 'long unsigned int') _Static_assert(*sizeof(my_arr) == 4, "");

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

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

Here 是 link 优先级 table。

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 首先,然后是前缀运算符 *sizeof).

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

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

sizeof 有两个 "versions":sizeof(type name)sizeof expression。前者需要一对 () 围绕其参数。但是后者——以表达式作为参数的那个——在它的参数周围没有 () 。您在参数中使用的任何 () 都被视为参数表达式的一部分,而不是 sizeof 语法本身的一部分。

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

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

认为 sizeof 的语法在其参数周围需要一对 () 是一种相当普遍的误解。在解释 sizeof(my_arr)[0].

等表达式时,这种误解会误导人们的直觉