泥淖--------------------大小端
声明:文章仅为个人总结所用,鄙人菜鸟,高手勿喷,欢迎批评指正。
经常看到通过联合体Union来判断系统是大端还是小端,而大家的解释通常都是:“联合体union的存放顺序是所有成员都从低地址开始存放,解答利用该特性,轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写。”而我却始终没有找到这句话是出自哪本书。
我知道unsigned short a = 0x1122在大端中存的话就是0x1122,而如果是在小端CPU上运行的话就是0x2211。疑问:
1. 那么如果取a的低八位即a&0xff的话,是不是在大端中是0x22,而在小端中就是0x11呢?
2. 那么如果a向右移位即a>>8取得其高八位的话,是不是再大端中是0x11,而在小端中就是0x22呢?
3. 那么如果将a赋值给unsigned char b,即b = (unsigned char)a,考虑到类型强转,取short型低八位赋值给char型,那么short型的低八位是多少呢?在大端中存的话,低八位是0x22,而在小端中存的话是0x11,那么是不是在不同架构的CPU上,结构就不相同呢?
4. 为什么通过联合体可以判断是大端还是小端?除了那个找不到出处的解释外,还有其他的解释吗?
5. 除了网上盛传的两种判断大小端的方法外,还有其他判断大小端的方法吗?
还是先列出网上盛传的其中一种判断方法吧:
void JudgeEndianByInt() { unsigned short temp = 0x1122; if(((char *)&temp)[0] == 0x11) { printf(_BIG_ENDIAN_); } else { printf(_Little_ENDIAN_); } }
我对这个函数的理解:直接根据大小端的定义来判断,如果该数据的低地址为存放的是该数据的低数据位,那么就是小端,否则就是大端。当然我也可以理解为,将指向short型数据的指针强制转换为char型指针,那么就要取其低地址赋值给char型指针,因此如果该低地址存放的是数据的低位,那么就是小端。
另外一种方法:
typedef union { int val_1; char val_2; }Union_Test; void JudgeEndianByUnion() { Union_Test u; u.val_1 = 0x11; if(u.val_2 == 0x11) { printf(_Little_ENDIAN_); } else { printf(_BIG_ENDIAN_); } }
我对这个函数的理解:其实这个判断和第一个判断原理是一样的,都是将同一个short型的内存区的值强制转换成char型的内存区,那么就要取其低位,如果地位存储的是低数据位,则是小端。
然后我来分析我的那么些个疑问。
1 2 ,位操作是针对二进制位的,是针对数据的二进制位的,不关乎内存地址的东西,所以不同平台不会有影响。
3. 也不会,强转的是数据的值,不是数据的地址,不会变化。
4. 有很多,只有能获得地址的方法或者根据地址进行判断的都是可行的,比如:
void JudgeEndianByMemory() { unsigned short temp = 0x11; unsigned char temp_2 = 0; memcpy(&temp_2,&temp,sizeof(temp_2)); if(temp_2 == 0x11) { printf(_Little_ENDIAN_); } else { printf(_BIG_ENDIAN_); } }
或者调用系统函数htonl ntohl等:
void HostToNet(ElemType val) { printf("val is 0x%x htonl(val) is 0x%x htonl(htonl(val)) 0x%x\n",val,htonl(val),htonl(htonl(val))); } void NetToHost(ElemType val) { printf("val is 0x%x ntohl(val) is 0x%x ntohl(ntohl(val)) 0x%x\n",val,ntohl(val),ntohl(ntohl(val))); }
因时间关系,今天暂时到此为止。
欢迎大家跟帖讨论,如有纰漏,欢迎指正,谢谢~