Chinaunix首页 | 论坛 | 博客
  • 博客访问: 153262
  • 博文数量: 31
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 360
  • 用 户 组: 普通用户
  • 注册时间: 2017-02-28 08:37
个人简介

没有绝活,怎能风骚.....

文章分类

全部博文(31)

文章存档

2017年(31)

我的朋友

分类: C/C++

2017-04-22 15:06:09

    计算机硬件有两种储存数据的方式:大端字节序(big endian小端字节序(little endian
举例:

    数值0x2211使用两个字节储存:高位字节是0x22,低位字节是0x11

    大端字节序:高位字节在前,低位字节在后,这是人类读写数值的方法

    小端字节序:低位字节在前,高位字节在后,即以0x1122形式储存。
    怎么去记才不会出错呢?
    其实只需要记住小端是低位字节存低位数据,高位字节存高位数据。(称为:低低高高)

同理:0x1234567的大端字节序和小端字节序的写法如下图:
    

    由图中可以看出:大端小端字节序最小单位为1字节,即8bit;大端字节序就是和我们平时写法的顺序一样,从低地址—>高地址写入0x01234567;而小端字节序就是和我们平时的写法反过来,因为字节序最小单位为1字节,所以从低地址—>高地址写入0x67452301

      我一直不理解为什么要有字节序,每次读写都要区分,很麻烦!觉得统一使用大端字节序,就很方便。

读了一篇文章,解答了所有的疑问,首先,为什么要有小端字节序?
    
原因是:计算机电路优先处理低位字节,效率比较高,因为计算机都是从低位开始的。所以计算机内部处理都是小端字节序。

    但是人类习惯读写大端字节序,所以除了计算机的内部处,其他的场合都是大端字节序,比如网络传输和文件储存。

    计算机处理字节序的时候,不知道什么是高位字节,什么是低位字节。它只知道按顺序读取字节,先读入第一个字节,再读第二个字节。如果是大端字节序,先读到的是就是高位字节,后读到的就是低位字节。小端字节序正好相反。

    字节序的处理:只有读取的时候,才必须区分字节序,其他情况都不用考虑。
    
    字节序大小端的问题是各公司笔试题的热门,基本上每家公司都会考这样的题目,下面举几个例子,大家一起看一下:
1.如何用程序测试一个平台是大端模式,还是小端模式?
    这题目答案不唯一,有好多种方法都可以实现,我在这里就举两种方法吧,因为其实用那种方法,实现的思想都是一样的。
    ①利用union类型--可以利用union类型数据的特点:所有成员的起始地址一致,1存放在变量i的低位,当变量ch等于1时,就相当于将数据的低位存放到了内存的低地址处,即就是小端模式,反之就是大端模式,代码如下:

点击(此处)折叠或打开

  1. #include <stdio.h>

  2. union check
  3. {
  4.   int i;
  5.   char ch;
  6. }c;

  7. int main()
  8. {
  9.   c.i = 1;
  10.   c.ch == 1 ? printf("Little-endian/n") : printf("Big-endian/n");
  11.   return 0;
  12. }
    ②对int强制类型转换,首先取出变量i的地址,强制转换为char *类型,再用*访问,代表取地址长度为1的内容,当取出内容等于1时,就相当于将数据的低位存放到了内存的低地址处,即就是小端模式,反之就是大端模式,

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. int main()
  4. {
  5.   int i = 1;
  6.   *(char *)&i == 1 ? printf("Little-endian/n") : printf("Big-endian/n");
  7.   return 0;
  8. }
   
下面再看一道比较难的题,因为不止涉及到大小端的问题,还涉及到强制类型转换的相关问题:

2.在X86系统下,分别在大端模式和小端模式下,下面函数的值是多少,为什么,请画图说明?
    int main()

    {

    int a[4] = {1, 2, 3, 4};

    int *ptr1 = (int *)(&a + 1);

    int *ptr2 = (int *)((int)a + 1);

    printf(“%x, %x, ptr1[-1], *ptr2);

    return 0;

     }
    我们知道a表示数组首元素的首地址,(int *)(&a+1)就是把&a加1,再转化为int *,因为&a+1就指向a[5]了,ptr1[-1]又相当于ptr1指向了a[4];

    还有(int)a+1就是把地址a转换int型加1,因为int类型是4个字节存储,(int)a+1就指向a[0]的第二个字节的指针了,如下图所示:

    所以小端模式时:ptr1[-1] = 0x04
                             *ptr2 = 0x2000000


    所以大端模式时:ptr1[-1] = 0x04
                             *ptr2 = 0x100


阅读(6838) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~