关于C#:为什么sizeof(my_arr)[0]编译并且相等sizeof(my_arr [0])?

Why does sizeof(my_arr)[0] compile and equal sizeof(my_arr[0])?

为什么要编译此代码?

1
2
3
4
_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()的计算结果应该是一个整型文字,不能将其视为数组。换句话说,它将以以下行失败的方式失败:

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

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

1
_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],它只是sizeof my_arr[0],带有多余的圆括号。

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

一般来说,在c.sizeof *a[i]++解析为sizeof (*((a[i])++))时,后缀操作符的优先级高于前缀操作符(先对a应用后缀操作符[]++,然后对前缀操作符*sizeof应用后缀操作符)。

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


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]这样的表达时误导人们的直觉的原因。


[]的进位比sizeof高。因此,sizeof(my_arr)[0]sizeof((my_arr)[0])相同。

这是指向优先表的链接。


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