为什么要编译此代码?
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( 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]++解析为sizeof (*((a[i])++))时,后缀操作符的优先级高于前缀操作符(先对a应用后缀操作符[]和++,然后对前缀操作符*和sizeof应用后缀操作符)。
(这是sizeof的表达式版本。还有一个类型版本,它采用带括号的类型名:sizeof (TYPE)。在这种情况下,需要parens和sizeof语法的一部分。)
- 我肯定知道sizeof是一元运算符而不是函数,但完全忘记了。胡扯。谢谢你的详细解释。不管怎样,[]的优先级高于*的事实很有趣。
- @蜜柚很有趣。我从来没有想过sizeof是一元运算符。
- 你不是说江户十一〔一〕吗?仅仅增加一个空间并不能真正改变任何事情。
- 我建议用sizeof((my_array)[0])代替
- 为什么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]这样的表达时误导人们的直觉的原因。
- 第一个版本的存在是为了让您可以在机器上(甚至没有64位机器时,从后面)检查整数的大小!,但int不是有效的表达式,因此不能将第二个窗体与它一起使用。
[]的进位比sizeof高。因此,sizeof(my_arr)[0]与sizeof((my_arr)[0])相同。
这是指向优先表的链接。
您使用的是以表达式为参数的sizeof运算符版本。与采用类型的类型不同,它不需要括号。因此,操作数只是(my_arr)[0],括号是多余的。