程序如下:
#include
#include
#include
int main(int argc, char** argv)
{
union
{
struct
{
char a:1;
char b:2;
char a:3;
}d;
char e;
} f;
f.e = 1;
printf("%d\n",f.d.a);
getchar();
return 0;
}
分析:
1.分析结构体(struct)中的含义.
char a:1; a占1位;
char b:2; b占2位;
char a:3; c占3位;
这个地方涉及到 struct 中的位段.随便Baidu,Google拉!
2.分析联合体(union)的含义.
union,共享内存,里面的数据是从低位开始的,这点很重要哦!
所以我们清楚,在 f.e = 1 之前, struct里面的内存是混乱的,因为没有初始化.
赋值之后,该Union中的内存应是下面的情况.("s"代表未知)
s s s s s s s s 1
3.这里我们假设是小端模式.(同样,大端模式,小端模式自己Baidu下拉,这里不罗嗦了)
4.printf("%d",f.d.a);
我们以 %d 的模式输出,因为此时读的是 a 所在的一位而 %d 需要32位.
怎么办呢,这个时候就需要类型提升了. (关于类型提升,照例去Baidu)
此时,1被作为符号位,做类型提升,使得 %d 读出的数据 32位全为 1.
即 0xFFFF.
5.0xFFFF,正是 -1 在内存中的补码形式. 所以这个程序会输出 -1.
延伸分析:
1.类型提升,是按照什么样的规则?
如果 a 不是占一位,而是占4位,5位,内存分布值为 10010/10100/01011 等等,会被提升成什么?
解答:首先提取符号位,也就是第一位.后面的原则未知.
2.大端模式和小端模式. 针对上题中的 char 类型,两者有区别么?
可以找一个大端模式的编译器,测试即得.
3.有兴趣的朋友可以尝试将 char类型改为 int/unsigned int,进行更多的调试.
4.关于原码,反码,补码.
众所周知,反码是原码各位取反,补码末位加1.我只想说,这不是绝对正确的.
有时间我会把真正的存储方式发上来,供大家研究.
5.关于赋值.
这需要有点ASCII的基础.因为ASCII可以表示char型常用的128个字符.(这些可以Baidu下)
此时将 char e 的值赋给了 这个 Union,所以 a,b,c 三个值都会有自己对应的位值.(0或者1)
不管我们赋的值是多少,只需保证最末一位是 1,也就是 a 的位是1,程序就会输出 -1.
提到ASCII码,让我想起了一个可以让windows死机的小程序.(只有几行代码,利用了ASCII码的控制符)
#include
#include
int main()
{
for(;;)
{
printf("hung up\t\t\b\b\b\b\b\b");
print("hung up\t\t\b\b\b\b\b\b";
}
return 0;
}
大概是这个样子,我记不太清楚了.还请高手留言赐教~!
阅读(1532) | 评论(0) | 转发(0) |