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
#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并使用它.
当地char foo完全隐藏typedef int foo在其范围内.foo隐藏后,您无法观察名称.尝试创建第二个typedef foo foo_t,或重命名一些东西,以避免"碰撞".