数据存储方式、传输方式、字节序问题总结


数据存储方式、传输方式、字节序问题很基础,但也很重要,下面简单总结一下:

1. 数据存储方式(主要以数值和字符类型的数据为例说明)
      1)数据(包括数值和字符)在计算机内存中都是以二进制的形式存放
      数值 --- 补码

      字符 --- 对应的ASCII码

常用数据类型及占用字节
数据类型占用字节数据类型占用字节
bool1unsigned int4
char1long4
short2unsigned long4
short int2float4
unsigned short2double8
int 4void*4
long int4enum4

       
     通过下面的举例,深入理解数值和字符在内存中的存储方式。
       定义变量:

         char szDig[4] = {0x11, 0x00, 0x11, 0x11};

         char szTmp[10] = {0x22, 0x00, 0x22, 0x22};

       【实验一】对szDig分别取strlen和sizeof操作,结果如下:
           strlen(szDig) = 2 (字符串结束符'/0'的ASCII码为0)

           sizeof(szDig) = 4

      【实验二】对szDig和szTmp进行strcat操作

           strcat(szTmp, szDig);

           结果szTmp数组中各项值为 (十六进制):11 22 00 00 00 00 ... ...  

       结论:对于非字符串,即便是char类型数组,也慎用strlen、strcat等字符串操作函数。
                   而如下的定义方式可以通过strlen取长度:
                   char szDig[] = "0000";

      
   2)整型数据在计算机内存中都是以补码的方式存放
      正数的补码是其本身
      负数的补码是其原码(除符号位外)各位取反,然后加1得到
      机器数有三种编码方式:原码、反码和补码。
      原码 --- 有效数值部分照抄,符号位正负(或者+-)分别用0 1表示。
      反码 --- 可由原码得到。
               正数的反码与原码一样;
               负数的反码是其原码(除符号位外)各位取反而得到。
      补码 --- 可由原码得到。
               正数的补码与原码一样;
               负数的补码是其原码(除符号位外)各位取反,并加1而得到。
               
      如,定义整型变量 a 和 b:
      char a, b;
      a = 1;
      b = -5;
      
      则,a(1)在内存中为 00000001
          b(-5)在内存中为 11111011
          即,-5 原码:10000101  反码:11111010  补码:11111011

               
   3)字符型数据在计算机内存中以其对应的ASCII码方式存放
      如,定义字符变量 cha 和 chb:
      char cha, chb;
      cha = 'x';
      chb = '1';
      
      则,cha('x')在内存中为 120,转换成二进制为 1111000
             chb('1')在内存中为 49,转换成二进制为 0110001


2.数据传输
   数据(包括数值和字符)在网络中也都是以二进制 0/1 方式传输,通信双方需提前约定好传输的为字符串还是数值,
   或者哪一部分是字符串,哪一部分是数值,以便接收方能够采用对应的方式读取准确的数据。
  
   借用网上的一个例子来说明数据的发送,如下:
   int i=999;
   char szBuf[1024] = {0};
   char *szTmp = "this is a character";
  
   memcpy(szBuf, &i, sizeof(int));
   memcpy(szBuf + sizeof(int), szTmp, strlen(szTmp));
  
   send(socket, szBuf, sizeof(int) + strlen(szInput), 0);
  
   无论是数值还是字符型的数据,都可以通过内存直接拷贝至待发送的buf。
   (需要注意的就是,不要对非字符串char数组采用strlen获取长度。)
   另外,需要考虑的就是下面要提到的字节序的问题。

  
3. 字节序
     掌握字节序之前,需要了解两个概念:网络字节序和主机字节序
     是否需要考虑字节序转换的两个条件:
     a)对于本地是小端序存储的设备来说,在准备进行网络数据传输时,需要考虑进行字节转换。
     b)如果要发送的数据在本地定义的数据类型(包括一些数据结构的成员)超过2字节,就发送时,就需要考虑字节序转换问题。
        比如,short、long类型的数据
        在发送时,需要分别使用 htons 和 htonl 进行字节序转换;
        在接收时,需要分别使用 ntohs 和 ntohl 进行字节序转换。
   
    下面借用网上一篇帖子来解释一下字主机序和网络序(http://www.cnblogs.com/jacktu/archive/2008/11/24/1339789.html)
   1)主机字节序
      不同的CPU有不同的字节序类型 这些字节序是指整数在内存中保存的顺序 这个叫做主机序 
      最常见的有两种
      ① Little endian:将低序字节存储在起始地址
      ② Big endian:将高序字节存储在起始地址
      
      LE little-endian (小端序)
      最符合人的思维的字节序 
      地址低位存储值的低位 
      地址高位存储值的高位 
      怎么讲是最符合人的思维的字节序,是因为从人的第一观感来说低位值小,就应该放在内存地址小的地方,
      也即内存地址低位。反之,高位值就应该放在内存地址大的地方,也即内存地址高位。
      
      BE big-endian (大端序)
      最直观的字节序 
      地址低位存储值的高位 
      地址高位存储值的低位 
      为什么说直观,不要考虑对应关系,只需要把内存地址从左到右按照由低到高的顺序写出,
      把值按照通常的高位到低位的顺序写出,两者对照,一个字节一个字节的填充进去。
      
      例子:在内存中双字0x01020304(DWORD)的存储方式 
                 内存地址 4000 4001 4002 4003 
                 LE 04 03 02 01 
                 BE 01 02 03 04 
      
      例子:如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为
                              big-endian  little-endian
                  0x0000     0x12        0xcd
                  0x0001     0x34        0xab
                  0x0002     0xab        0x34
                  0x0003     0xcd        0x12
                  x86系列CPU都是little-endian的字节序. 
   
   2)网络字节序
       网络字节顺序,是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,
       从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式。
      
       socket编程时,尤其需要注意网络字节序的问题,有下面四个字节序转换函数:
        htons  将unsigned short类型从主机序转换到网络序
        htonl  将unsigned long类型从主机序转换到网络序
        ntohs  将unsigned short类型从网络序转换到主机序
        ntohl  将unsigned long类型从网络序转换到主机序
      
      在使用little endian的系统中 这些函数会把字节序进行转换;
      在使用big endian类型的系统中 这些函数会定义成空宏。
      
      同样,在网络程序开发时,或是跨平台开发时,也应该注意保证只用一种字节序,不然两方的解释不一样就会产生bug。
      
      注:
      ① 网络与主机字节转换函数:htons ntohs htonl ntohl (s 就是short l是long h是host n是network)
      ② 不同的CPU上运行不同的操作系统,字节序也是不同的,参见下表。
         处理器                操作系统    字节排序
         Alpha                  全部           Little endian
         HP-PA                 NT             Little endian
         HP-PA                UNIX          Big endian
         Intelx86               全部          Little endian <--- x86系统是小端字节序系统
         Motorola680x    全部          Big endian
         MIPS                    NT            Little endian
         MIPS                    UNIX        Big endian
         PowerPC            NT            Little endian
         PowerPC           非NT         Big endian  <--- PPC系统是大端字节序系统
         RS/6000           UNIX          Big endian
         SPARC              UNIX         Big endian

         IXP1200 ARM   全部          Little endian


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值