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


129

为什么要编译此代码?

_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


15
我怀疑( sizeof( my_arr ) )[ 0 ]失败了。
安德鲁·亨利

最近的重复版本在语法上有另一个变化:为什么sizeof(x)++可以编译?
彼得·科德斯

Answers:


197

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语法的一部分。)


14
我绝对知道sizeof是一元运算符而不是函数,但是完全忘记了。哎呀 感谢您的详细解释。无论如何,[]的优先级都比*高。
bgomberg '17

@melpomene有趣。我从未想过sizeof要成为一元运算符。
突变键盘

5
不是"... parses as sizeof (my_arr[0])"吗 仅添加一个空格并不会真正改变任何东西。
伯恩哈德·巴克

我会建议sizeof((my_array)[0]),而不是
bolov


46

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]


1
第一个版本已存在,因此您可以在计算机上检查整数(通常从64位计算机开始!),但是int它不是有效的表达式,因此您不能使用第二种形式。
NH。

25

[]比...具有更高的优越性sizeof。因此sizeof(my_arr)[0]与相同sizeof((my_arr)[0])

是优先级表的链接。


8

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.