在这种情况下,C是否正确处理sizeof(...)和sizeof ...

时间:2017-11-15 01:15:13

标签: c sizeof unary-operator

在以下代码中,函数testtest2是否等效?

typedef int rofl;

void test(void) {
    rofl * rofl = malloc(sizeof(rofl)); // Is the final rofl here the TYPE?
}

void test2(void) {
    rofl * rofl = malloc(sizeof *rofl); // Is the final rofl here the VARIABLE?
}

换句话说:

  1. 由于括号,rofl中的sizeof(rofl)是否正确选择rofl 类型
  2. 由于缺少括号,rofl中的sizeof *rofl是否正确选择了rofl 变量
  3. 注意:这是一个看起来很愚蠢的例子,但在实践中实际上可能会发生一个类型名称与变量名称相同的名称。因此问题。

3 个答案:

答案 0 :(得分:27)

在这两种情况下,最后一个rofl是变量名称。变量名一出现就在范围内;对于当前范围的其余部分,普通上下文(*)中的标识符始终表示变量名称。

sizeof运算符不会为名称查找引入任何特殊情况。实际上,没有语言结构会使用标识符的隐藏含义。

在实践中,最好不要对类型和变量名使用相同的标识符。

(*)标识符有三个特殊的上下文:标签名称,结构标签和结构成员。但在所有其他上下文中,所有标识符共享一个公共名称空间:类型名称与变量名称与函数名称等没有明确的标识符名称空间。

这是一个人为的例子:

typedef int A;      // "A" declared as ordinary identifier, meaning a type name

struct A { A A; };  // "A" declared as struct tag and member name -- OK as these are three different name spaces. Member type is "int"

A main()            // int main() - ordinary context
{
    struct A A();   // "A" declared as ordinary identifier, meaning a function name; hides line 1's A
    // A C;         // Would be error: ordinary A is a function now, not a typedef for int
    struct A B;     // OK, struct tags have separate name space
    A:+A().A;       // OK, labels and struct members have separate name space, calls function
    goto A;         // OK, label name space
}

答案 1 :(得分:13)

在此声明中

rofl * rofl = malloc(sizeof(rofl)); // Is the final rofl here the TYPE?

变量rofl的名称隐藏了typedef名称rofl。因此,在sizeof运算符中,使用了指针rofl,该表达式具有类型int *

同样适用于此声明

rofl * rofl = malloc(sizeof *rofl); 

除了使用带有解除引用的指针rofl的表达式,该指针具有typedef名称rofl的类型int

似乎由于这个C语法定义而引起混淆

sizeof unary-expression
sizeof ( type-name )

但是unary-expression可以是一个主表达式,它是括在括号中的表达式。

来自C标准(6.5.1主表达式)

primary-expression:
    ( expression )
    //...

因此,例如,如果x是变量的名称,那么您可以编写

sizeof x 

sizeof( x )

为清楚起见,您可以在sizeof运算符和主表达式之间插入空格

sizeof    ( x )
operator  primary expression

为了比较,考虑另一个一元运算符:一元加号。你可以写例如

+ x

+ ( x )

现在只需将一元加号替换为另一个一元运算符sizeof

至于隐藏名称,问题可以解析为结构,联合和枚举,因为它们的名称包含标记的关键字。

例如

typedef struct rofl { int x; } rofl;

void test(void) {
    rofl * rofl = malloc(sizeof( struct rofl));
}

在使用sizeof运算符的此函数中,使用了类型名称struct rofl

在此功能中

typedef struct rofl { int x; } rofl;

void test(void) {
    rofl * rofl = malloc(sizeof( rofl));
}

使用sizeof运算符时,使用了具有变量rofl的主表达式,其类型为struct rofl *

答案 2 :(得分:2)

没有涉及“挑选”或“选择”。在这两种情况下,由于范围规则,每个rofl调用中引用的sizeof是变量,而不是类型。变量在内部范围声明,因此会覆盖类型名称。 sizeof运算符的参数括号内无关紧要。

祝你好运。