是否在一个变量上使用sizeof,其中存在一个同名的类型?

dhe*_*ein 13 c sizeof undefined-behavior

这是明确定义的行为还是未定义/以其他方式定义哪些foo(数据类型或标识符)sizeof将在哪些操作?

typedef int foo;

int main(int argc, char *argv[])
{
    char foo;
    printf ("%u\r\n", sizeof(foo));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果它定义得很好,有没有办法可以获得数据类型的大小foo而不声明该类型的变量只sizeof在其上使用?

Sou*_*osh 11

这是明确定义的行为还是未定义

这是明确定义的行为.

在你的代码中

printf ("%u\r\n", sizeof(foo));
Run Code Online (Sandbox Code Playgroud)

foo毫不含糊.外部局部内部 foo "阴影"(或隐藏).所以,它本质上是 foo

printf ("%u\r\n", sizeof(char));
Run Code Online (Sandbox Code Playgroud)

引用C11,章节§6.2.1,"标识符的范围",(强调我的)

如果标识符指定同一名称空间中的两个不同实体,则范围可能会重叠.如果是这样,一个实体(内部范围)的范围将严格地在另一个实体(外部范围)的范围之前结束.在内部范围内,标识符指定在内部范围内声明的实体; 在外部作用域中声明的实体在内部作用域内隐藏(并且不可见).

现在,回答第二部分,

如果定义得很好,有没有办法可以获得数据类型的大小foo而不声明该类型的变量只用于sizeof它?

好吧,内部 foo标识符的范围它的定义之后开始(作为char类型变量).因此,如果变量定义之前使用foo(typedefed类型),您将实际看到全局定义,直到那时,变量不存在以"遮蔽"全局标识符.foofoofoo

正如提到的其他答案Purag先生,你一定能够做这样的事情

#include <stdio.h>

typedef int foo;

int main(void)
{
    printf ("%zu\n", sizeof foo); /* will cosider the global */
    char foo = 0;                 /* Global definition gets shadowed here*/
    printf ("%zu\n", sizeof foo); /* The local definition of 'foo' is only visible*/ 
                                  /* till the end of the block (function)*/

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

也就是说,作为一个注释,sizeof运算符的结果类型是size_t.您应该使用%zu格式说明符来打印结果.


Pur*_*rag 11

C没有明确的范围解析,因此在打开新范围时可以重用和覆盖标识符(变量名,typedef名,结构名等).当重用标识符时,该标识符保持的先前上下文不再可见.

在您的特定代码中,范围typedef是全局的,因此typedef在编译包中的任何位置都可见.但是,您使用函数声明打开一个新范围,并在该新范围中定义一个使用与该标识符相同的标识符的变量typedef.现在,该标识符引用变量而不是类型; 意思是,直到变量的范围结束(函数的结尾),才typedef完全隐藏.

回想一下C是线性编译的,所以你可以做这样的事情来解决发生屏蔽的问题:

#include <stdio.h>
typedef int foo;

int main()
{
    printf ("%zu\n", sizeof (foo)); /* #1 */

    char foo;
    printf ("%zu\n", sizeof foo); /* #2 */

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在#1点,请注意char foo由于编译器尚未达到其声明,因此尚未打开变量的范围.(所有编译器都会在堆栈上为变量分配空间).

因此foo,此时的使用仍然是参考全局定义的typedef.

当你点击#2时,声明变量并正式启动变量的生命周期,这意味着标识符现在用于不同的实体.它屏蔽了当前块范围(由函数声明启动)的全局定义foo.

这是良好的文档行为; 网上有一份C标准草案,但必须购买已公布的标准.草案在第6.2.1节中说:

如果标识符指定同一名称空间中的两个不同实体,则范围可能会重叠.如果是这样,一个实体(内部范围)的范围将严格地在另一个实体(外部范围)的范围之前结束.在内部范围内,标识符指定在内部范围内声明的实体; 在外部作用域中声明的实体在内部作用域内隐藏(并且不可见).资源

请注意,这不是神奇的或任何东西......这都是在编译时完成的.编译器有一个标识符表和它们引用的东西,新范围为这些创建新表.碰巧在上面的代码中的#1点,编译器还没有使用new填充表char foo(这是由于线性编译).因此,当它转换第一printf行时,它会查看所有活动范围以查找标识符foo,并查看typedef并使用它.在第二步printf,它查看所有活动范围,并查找标识符的更新近期使用foo并使用它.


Pot*_*ter 6

当地char foo完全隐藏typedef int foo在其范围内.foo隐藏后,您无法观察名称.尝试创建第二个typedef foo foo_t,或重命名一些东西,以避免"碰撞".