为什么(以及何时)在 sizeof 后需要使用括号?

96

以下内容无法编译:

typedef int arr[10];
int main(void) {
    return sizeof arr;
}

sizeof.c:3: error: expected expression before ‘arr’

但是如果我将它更改为

sizeof(arr);

一切都好,为什么呢?


在ANSI-C中,sizeof作为操作符是不可用的。 - Grim
2
@Kostya:我的《C程序设计语言》(我所拥有的最早描述C语言的书籍)离我很远,现在无法查看,但我可以百分之百确定它与C99标准对sizeof的描述是基本相同的。自1989年ANSI标准化C语言之前,sizeof就已经存在了。 - pmg
@Grim,你的说法“sizeof作为运算符在ansi-c中不可用”是错误的。C90有一个3.3.3.4节“sizeof运算符”。在C99中,它移动到了6.5.3.4节。 - Roland Illig
3个回答

138

根据6.5.3,sizeof有以下两种形式:

sizeof unary-expression
sizeof ( type-name )

由于你代码中的 arr 是一个 type-name,因此它必须加上括号。


19
+1 为了强调 sizeof 是一个运算符:括号应该与类型一起使用,而不是与运算符一起使用。 - pmg
7
@pmg: 我认为括号“属于”哪个部分并不清楚。第二种形式的语法由三个标记和一个非终端组成:“sizeof ( type-name )”。但对于第一种形式,你可以编写例如sizeof(x),虽然它看起来像是一个函数调用(如果'sizeof'不是关键字),但实际上它是应用于带括号表达式的运算符。这是你想要的吗? - Keith Thompson
3
我的意思是,sizeof的语法是 sizeof <SOMETHING>,而不像函数,例如 printfprintf ( <SOMETHING> )。括号属于 printf,但不属于 sizeof。当 sizeof 应用于括号中的类型名称时,我认为它类似于对无内容进行转换,仅“返回”类型。 - pmg
3
@pmg:你当然可以这样想,但我认为这种想法是误导性的。它与强制转换的相似之处仅在于它在括号中具有类型名,这只是语法上的巧合。我更愿意将sizeof (type-name)视为一种独立的表达式。(标准将其称为运算符,但(type-name)并不是通常意义下的操作数。) - Keith Thompson
1
@melpomene 一个更常见的写法是 sizeof("abcdefghij"[0]),而不是 sizeof(0)["abcdefghij"]。参见 https://dev59.com/83RC5IYBdhLWcg3wMd9S/ - jcsahnwaldt Reinstate Monica
显示剩余3条评论

57

这就是语言的规定,这里必须给类型名称加上括号。

假设语法看起来像这样:

sizeof 一元表达式 sizeof (类型名称)

现在,例如以下表达式将是模糊不清的:

sizeof int * + 0

这可能是 sizeof(int *) + 0 或者是 sizeof(int) * +0。对于一元表达式来说不会出现歧义,因为在表达式后面添加一个星号不是一个表达式(但对于某些类型名来说,再次添加一个星号又成为了一个类型名)。

这里必须指定一些内容,要求类型名必须加括号就是解决这种歧义的方法。


-4

我认为这是因为你使用了typedef。如果你将其移除,它应该可以编译。

维基百科的例子:

/* the following code fragment illustrates the use of sizeof     
 * with variables and expressions (no parentheses needed),
 * and with type names (parentheses needed)    
 */
char c;
printf("%zu,%zu\n", sizeof c, sizeof (int));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接