为什么sizeof int是错误的,而sizeof(int)是正确的?

104

我们知道sizeof是一个用于计算任何数据类型和表达式大小的运算符,当操作数是一个表达式时,括号可以省略。

int main()
{
        int a;

        sizeof int;
        sizeof( int );
        sizeof a;
        sizeof( a );

        return 0;
}

sizeof 的第一个用法是错误的,而其它用法是正确的。

使用 gcc 编译时,会得到以下错误信息:

main.c:5:9: error: expected expression before ‘int’

我的问题是为什么C标准不允许这种操作。 sizeof int 是否会引起任何歧义?


7
有趣的是,并非所有的表达式都不需要括号就可以被接受:试试 sizeof (int)a - Fred Foo
2
@MikkelK.:OP正在询问标准引用的原因,他已经知道了被标记答案中提到的引用。 - Alok Save
2
@Lundin: sizeof +(int)a 相较于 *& 有一个实际编译的优势^-^ - Steve Jessop
2
@SteveJessop 哦,对了,它不是一个左值。尽管在 Embarcadero C++ 中编译通过,但这很奇怪。无论如何,我相信我们刚刚发现了一种使用一元+运算符的方法!这肯定是 C 编程历史上的第一次 :) - Lundin
3
@Lundin:在使用一元运算符 + 时仍需谨慎。例如,由于整数提升,sizeof +(char)a == sizeof(int) ,如果对要求取大小的表达式存在任何疑虑,最好还是加上括号以避免错误产生。因此我不确定是否应将其称为“用法”,尽管我承认我确实使用过...。 - Steve Jessop
显示剩余3条评论
3个回答

107
以下可能会存在歧义:
sizeof int * + 1

这是(sizeof (int*)) + 1还是(sizeof(int)) * (+1)?显然C语言可以引入规则来解决歧义,但我可以想象为什么它没有烦恼。在目前的语言中,类型说明符从未在表达式中“裸露”出现,因此无需制定规则来解决那个第二个*是类型的一部分还是算术运算符。

现有的语法已经解决了可能存在的sizeof (int *) + 1的歧义。它是(sizeof(int*))+1,而不是sizeof((int*)(+1))

C++需要解决类似的问题,其函数样式的转换语法也可能遇到类似的问题。你可以写int(0),也可以写typedef int *intptr; intptr(0);,但你不能写int*(0)。在这种情况下,规则是“裸露”的类型必须是简单类型名称,它不能只是任意旧的类型标识符,可能有空格或尾随标点符号。也许sizeof可以被定义为具有相同限制,但我不确定。


1
C++有new int*(X),如果C++没有指定new运算符采用可能是类型的最长字符串,则会产生歧义。因此,在C++中,他们可以使用sizeof来做同样的事情,我想。但在C++中,您可以说sizeof int(),这将会产生歧义(类型或值初始化int?)。 - Johannes Schaub - litb
@JohannesSchaub-litb:嗯,也许C++可以说,如果可以解析一个类型,则优先选择该类型,否则它是一个表达式。这种歧义将得到解决,但sizeof int()将是不合法的(“没有size_toperator()”),我认为这将是不受欢迎的! - Steve Jessop

31

来自 C99标准

6.5.3.4.2
sizeof 运算符返回其操作数的大小(以字节为单位),其操作数可以是表达式或括在圆括号中的类型名。

在您的情况中,int 既不是表达式也不是括在圆括号中的类型名。


12
我不明白为什么这个回答获得了7个赞,就像那三个被删除的回答一样,它只是重复了规则,而没有解释规则存在的原因。 - Fred Foo
8
@larsmans,是的,我同意你的观点。尽管它不断重复规则,但至少给予了一份授权阅读材料。 - Yishu Fang
3
如果我们开始试图为C99中做出的每个决定提供理由,那么我们会在这里呆上一整年。引用标准就像任何其他方法一样,可以结束这次讨论。 - Perry
1
@Perry:如果您不喜欢这种类型的问题,可以投票将问题标记为有争议。 - Fred Foo
4
作为一个不熟悉C++的人,我甚至能够理解这个答案。如果你能阅读和理解英文,那我不确定问题出在哪里。 - Kev
+1 令我困惑的是,int;可以编译。因此我错误地认为它也必须是一个_expression_。在查看您提供的标准后,发现有一些语法规则(6.7): declaration: declaration-specifiers init-declarator-list[opt] ;declaration-specifiers: type-specifier declaration-specifiers[opt],和type-specifier: int定义了int;作为一个_declaration_,而不是_expression_([opt]表示可选)。感谢引用和链接的文档。 - Alberto

7

C语言中使用sizeof运算符有两种方式。语法如下:

C11 6.5.3 Unary operators
...
sizeof unary-expression
sizeof ( type-name )

每当您使用类型作为操作数时,根据语言的语法定义,必须加上括号。如果您在表达式中使用sizeof,则不需要括号。
C标准提供了一个这样的示例,您可能希望在表达式上使用它:
sizeof array / sizeof array[0]

然而,为了保持一致性,并避免与运算符优先级相关的错误,我个人建议在任何情况下都使用 ()。


@JohannesSchaub-litb,我同意它没有提供C标准委员会在指定C90标准时的推理。你必须问他们...但是,它确实回答了问题,但是由于语法如6.5.3所指定,C不允许这样做。 OP似乎也不知道sizeof expressionsizeof(type)之间的区别,在此答案中有解释。 - Lundin
(仅供参考,我刚刚阅读了C90和C11的解释,但两者都没有提供任何解释。) - Lundin
1
我怀疑这并没有必要的理由,这只是原始C语言设计者决定这样做的方式。也许这样做对早期解析器来说更容易一些。我本打算发表一个关于typedef和变量共享相同命名空间的答案,但这并不排除允许第一种语法的可能性;只需要解析规则表明当没有括号时优先选择变量,有括号时优先选择类型,并且在名称无歧义时可以使用任何形式。由于没有必要改变它,标准委员会就将其保持不变。 - Barmar

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