近来在ubuntu下开发c,网络编程方面的,遇到网络字节序,和本地字节序 大小端的问题。
1、判断大小端的简单方法:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
unsigned int i = 1;
if(*((char*)&i) == 0)
{
printf("this is big endian. \n");
}
else if(*((char*)&i) == 1)
{
printf(" this is little endian. \n");
}
else
{
printf("sorry, i do not know . \n");
}
return 0;
}
结果是:(如图)
当然,windows和ubuntu系统都是little endian 系统。
分析:
整形变量 i 在内存中占4个字节,所以有 32位;下图中显示的是:每个字节是 8 位二进制的数字,用 2 位十六进制表示 。所以 0x 0000 0001,表示 32 位 二进制数字, 是变量 i 在内存中的表示。(16进制的8位表示的是内存中的4个字节)
而指针指向最低位,所以上面的程序可以检测大小端的问题。
并且如果是大端的话,当前地址加3位 (+ 3)便得到了最末位的数值,末位为 ‘01’。(下图中红笔的指向)
所以有下面的代码并且相应的结果是:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
unsigned long i = 1;
if(*((char*)&i) == 1)
{
printf("this is little endian.\n");
printf("i == %p . %d, \n", ((char*)&i)+0, *(((char*)(&i))+0) );//
printf("i+1 == %p . %d, \n" , ((char*)&i)+1, *(((char*)(&i))+1));//高一个字节
printf("i+2 == %p . %d, \n" , ((char*)&i)+2, *(((char*)(&i))+2));//高二个字节
printf("i+3 == %p . %d, \n" , ((char*)&i)+3, *(((char*)(&i))+3));//高三个字节
printf("i-1 == %p . %d,\n", *(((char*)(&i))-1) , ((char*)&i)-1);//低一个字节
printf("i+4 == %p . %d,\n", *(((char*)(&i))+4) , ((char*)&i)+4);//高四个字节
}
else if(*((char*)&i) == 0)
{
printf("this is big endian. \n");
}
else
{
printf("i do not know. \n");
}
return 0;
}
结果:
即:在 i 的指针,所指向的空间存储的是:0000 0001 ,高一个字节的位置存储的是 0000 0000,高两个字节,和高三个字节也是 0000 0000。
但是 高四个字节和低一个字节的位置存储的是 不定的数值。
2、htonl()和ntohl()方法的学习
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
int main(void)
{
unsigned long i = 1;
if(*((char*)&i) == 1)
{
printf("this is little endian.\n");
}
else if(*((char*)&i) == 0)
{
printf("this is big endian. \n");
}
else
{
printf("i do not know. \n");
}
i = ntohl(i);
printf("%lu \n", i);
printf("%#x \n", i);
printf("%#o \n", i);
i = ntohl(i);
printf("%lu \n", i);
printf("%#x \n", i);
printf("%#o \n", i);
return 0;
}
结果为:
结果分析:
(1)、是把内存中的二进制: 00000000 00000000 00000000 00000001,
按照字节反转过来为: 00000001 00000000 00000000 00000000 ,
自然数2的24次方结果为16777216
转换成十进制为: 16777216;
转换成十六进制为:0x0100 0000;
转换成八进制为:o 010 0000 0000。(红色的0x和o代表是十六进制和八进制)
(2)、从两个方法来看,htonl和ntohl都是实现了反转;并且经过验证,上面的ntohl()方法,和htonl()方法,都可以互换;
所以两个方法内部的实现应该是一样。