精华内容
下载资源
问答
  • 本程序主要是将十进制转十六进制函数(包括正负整数及小数),并根据设置显示大小端。输入参数说明:x表示十进制数,N表示最后转换成的十六进制数的位数(字节数),flag表示大小端(1是小端,2是大端)
  • 二进制文件大小端转换工具,单独工具;二进制文件大小端转换工具,单独工具;二进制文件大小端转换工具,单独工具
  • 今天跟大家分享的是判断CPU大小端模式的两种经典方法,一起来学习一下
  • 本程序主要是将十进制转十六进制函数(包括正负整数及小数),并根据设置显示大小端。 输入参数说明:x表示十进制数,N表示最后转换成的十六进制数的位数(字节数),flag表示大小端(1是小端,2是大端)
  • 数据大小端的介绍 大小端数据模式的转换 按位运算,左移、右移运算 大小端以及一些数据补位 一、数据大小端的介绍  网上关于数据大小端的介绍一大堆,为了让文章全面点,本文也就这方面简单说明一下。 a. 大小端...
  • 本文介绍了用C语言程序判断大小端的方法,与大家分享一下。
  • Float类型大小端转换测试程序 1、方法一使用了联合体。联合(union)变量的所有成员共享同片存储区/内存。 2、方法二使用了数组。
  • 大小端测试程序

    2018-08-21 10:03:56
    大小端测试测序, 可以很方便的测试机器的大小端格式
  • 大小端字节序的介绍和相互转换。在c++中,有4个函数可以实现主机字节序到网络字节序的相互转换。
  • linux c 判断大小端代码示例 linux c 判断大小端代码示例
  • linux c 判断大小端代码union方式
  • 1、在位数选择选择框选择需要转换的长度是16位还是32位,一般嵌入式固件的应该是32位大小端转换。 2、起始位置是指从文件的哪个位置开始转换,一般默认为0。 3、字节合并的意思是文件二进制内容如果是”01 02 03 04 ...
  • java实现使用javolution完成数据接收过程中大小端转换的问题
  • 大小端转换(C++)

    2014-01-10 21:58:56
    提供一个大小端转换的类,可以转换short int float double类型,提供一个大小端转换的类,可以转换short int float double类型,提供一个大小端转换的类,可以转换short int float double类型
  • 大小端

    千次阅读 2018-11-22 18:55:26
    首先先解释一下大小端的概念 大端就是数据的高字节存在内存的低地址,低字节存在内存的高地址 小端就是数据的高字节存在内存的高地址,低字节存在内存的低地址 #include <stdio.h> #include &...

    首先先解释一下大小端的概念

    大端就是数据的高字节存在内存的低地址,低字节存在内存的高地址

    小端就是数据的高字节存在内存的高地址,低字节存在内存的低地址

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void)
    {
    	union{
    		short s;
    		char c[4];
    	}un;
    	un.s = 010101;
    	if (un.c[0] == 16 && un.c[1] == 65)
    		printf("big-endian\n");
    	else if (un.c[0] == 65 && un.c[1] == 16)
    		printf("little-endian\n");
    	else
    		printf("unknown\n");
    	system("pause");
    }

    如何判断大小端

    我们可以使用联合体,利用联合体的特性,所有元素都是从低地址开始存放,而且所有元素共享空间,由上面代码便可以判断大小端。通过判断,便可以知道我们所使用的机器是大端还是小端。当然大小端跟CPU和所使用的擦做系统有关,Intelx86CPU下的机器都是小端。

    需要考虑大小端的场景

    两台大小端不同的机器在网络上传输需要考虑大小端,因为大小端不同,字节存放次序不同,那么这时就需要转换大小端,这时就需要用到网络字节序。

    网络字节序

    在tcp/ip协议中把接收到的第一个字节当作高位字节看待,这要求发送端发送的第一个字节是高字节;而在发送端发送数据时,发送的第一个字节是该数值在内存中的起始地址处对应的那个字节,也就是说,该数值在内存中的起始地址处对应的那个字节就是要发送的第一个高位字节(即:高位字节存放在低地址处),因此网络字节序是大端。

     

    展开全文
  • C/C++ 大小端判断

    2013-01-16 16:44:36
    大小端 C/C++语言 面试中如果能写出一定赢的喝彩
  • 大小端详解(判断+转换)

    万次阅读 多人点赞 2019-04-25 00:14:46
    一、什么是大端和小 所谓的大端模式,就是高位字节排放在内存的低地址,低位字节排放在内存的高地址。 所谓的小模式,就是低位字节排放在内存的低地址,高位字节排放在内存的高地址。 简单来说:大端...

    一、什么是大端和小端

    所谓的大端模式,就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

    所谓的小端模式,就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

    简单来说:大端——高尾端,小端——低尾端

    举个例子,比如数字 0x12 34 56 78在内存中的表示形式为:

    1)大端模式:

    低地址 -----------------> 高地址

    0x12  |  0x34  |  0x56  |  0x78

    2)小端模式:

    低地址 ------------------> 高地址

    0x78  |  0x56  |  0x34  |  0x12

    可见,大端模式和字符串的存储模式类似。

    3)下面是两个具体例子:

    16bit宽的数0x1234在Little-endian模式(以及Big-endian模式)CPU内存中的存放方式(假设从地址0x4000开始存放)为:

    内存地址小端模式存放内容大端模式存放内容
    0x40000x340x12
    0x40010x120x34

    32bit宽的数0x12345678在Little-endian模式以及Big-endian模式)CPU内存中的存放方式(假设从地址0x4000开始存放)为:

    内存地址小端模式存放内容大端模式存放内容
    0x40000x780x12
    0x40010x560x34
    0x40020x340x56
    0x40030x120x78
     

    4)大端小端没有谁优谁劣,各自优势便是对方劣势:

    小端模式 :强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。
    大端模式 :符号位的判定固定为第一个字节,容易判断正负。

    二、数组在大端小端情况下的存储:

      以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示value:
      Big-Endian: 低地址存放高位,如下:
    高地址
            ---------------
            buf[3] (0x78) -- 低位
            buf[2] (0x56)
            buf[1] (0x34)
            buf[0] (0x12) -- 高位
            ---------------
            低地址
    Little-Endian: 低地址存放低位,如下:
    高地址
            ---------------
            buf[3] (0x12) -- 高位
            buf[2] (0x34)
            buf[1] (0x56)
            buf[0] (0x78) -- 低位
            --------------
    低地址

    三、为什么会有大小端模式之分呢?

    这是因为在计算机中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8 bit。但是在C 语言中除了 8 bit 的char之外,还有 16 bit 的 short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型 x ,在内存中的地址为 0x0010,x 的值为0x1122,那么0x11位高字节,0x22位低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。

    四、如何判断机器的字节序 (重点)

    一般都是通过 union 来测试的,下面这段代码可以用来测试一下你的编译器是大端模式还是小端模式:

    
     
    1. #include <stdio.h>
    2. int main (void)
    3. {
    4. union
    5. {
    6. short i;
    7. char a[ 2];
    8. }u;
    9. u.a[ 0] = 0x11;
    10. u.a[ 1] = 0x22;
    11. printf ( "0x%x\n", u.i); //0x2211 为小端 0x1122 为大端
    12. return 0;
    13. }
    14. 输出结果:
    15. 0x2211

    union 型数据所占的空间等于其最大的成员所占的空间。对 union 型的成员的存取都是相对于该联合体基地址的偏移量为 0 处开始,也就是联合体的访问不论对哪个变量的存取都是从 union 的首地址位置开始

    联合是一个在同一个存储空间里存储不同类型数据的数据类型。这些存储区的地址都是一样的,联合里不同存储区的内存是重叠的,修改了任何一个其他的会受影响。

    参看:C语言再学习 -- 结构和其他数据形式

    1. 共用体声明和共用体变量定义
    共用体(参考“共用体”百科词条)是一种特殊形式的变量,使用关键字union来定义
    共用体(有些人也叫"联合")声明和共用体变量定义与结构体十分相似。其形式为:
    union 共用体名{
    数据类型 成员名;
    数据类型 成员名;
    ...
    } 变量名;

    参看:

    共用体表示几个变量共用一个内存位置,在不同的时间保存不同的数据类型和不同长度的变量。在union中,所有的共用体成员共用一个空间,并且同一时间只能储存其中一个成员变量的值

    下例表示声明一个共用体foo:

    
     
    1. union foo{ /*“共用”类型“FOO”*/
    2. int i; /*“整数”类型“i”*/
    3. char c; /*“字符”类型“C”*/
    4. double k; /*“双”精度类型“K”*/
    5. };

    再用已声明的共用体可定义共用体变量。例如,用上面说明的共用体定义一个名为bar的共用体变量, 可写成:
    union foo bar;
    在共用体变量bar中, 整型变量 i 和字符变量 c 共用同一内存位置。

    当一个共用体被声明时, 编译程序自动地产生一个变量, 其长度为联合中最大的变量长度的整数倍。以上例而言,最大长度是double数据类型,所以foo的内存空间就是double型的长度。

    
     
    1. union foo /*“共用”类型“FOO”*/
    2. {
    3. char s[ 10]; /*“字符”类型的数组“S”下面有“10”个元素*/
    4. int i; /*“整数”类型i*/
    5. };

    在这个union中,foo的内存空间的长度为12,是int型的3倍,而并不是数组的长度10。若把int改为double,则foo的内存空间为16,是double型的两倍。

    2. 共用体和结构体的区别
    1)共用体和结构体都是由多个不同的数据类型成员组成, 但在任何同一时刻, 共用体只存放了一个被选中的成员, 而结构体的所有成员都存在。
    2.)对于共用体的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构体的不同成员赋值是互不影响的。

    总结:

    恍然大悟,union 联合之前还是没有理解透。一开始不太理解,为什么给 a[0]、a[1] 赋值,i 没有定义啊,为什么会有值呢,或者值为什么不是随机数呢?现在明白了,我们为什么用 union 联合来测试大小端,在联合变量 u 中, 短整型变量 i 和字符数组 a 共用同一内存位置。给 a[0]、a[1] 赋值后,i  也是从同一内存地址读值的。

    知道这层关系后,那么通过强制类型转换,判断其实存储位置,也可以测试大小端了:

    
     
    1. #include <stdio.h>
    2. int main (void)
    3. {
    4. short i = 0x1122;
    5. char *a = ( char*)(&i);
    6. printf ( "0x%x\n", *(a + 0)); //大端为 0x11 小端为 0x22
    7. printf ( "0x%x\n", *(a + 1));
    8. return 0;
    9. }
    10. 输出结果:
    11. 0x22
    12. 0x11

     

    说明:上面两个例子,可以通过 if 语句来判断大小端,这里只是介绍方法。

    五、常见的字节序

    一般操作系统都是小端,而通讯协议是大端的。

    1)常见CPU的字节序

    Big Endian : PowerPC、IBM、Sun
    Little Endian : x86、DEC
    ARM既可以工作在大端模式,也可以工作在小端模式。

    2)常见文件的字节序

    Adobe PS – Big Endian
    BMP – Little Endian
    DXF(AutoCAD) – Variable
    GIF – Little Endian
    JPEG – Big Endian
    MacPaint – Big Endian
    RTF – Little Endian

    另外,Java和所有的网络通讯协议都是使用Big-Endian的编码。

    六、如何进行大小端转换(重点)

    第一种方法:位操作

    
     
    1. #include<stdio.h>
    2. typedef unsigned int uint_32 ;
    3. typedef unsigned short uint_16 ;
    4. //16位
    5. #define BSWAP_16(x) \
    6. (uint_16)((((uint_16)(x) & 0x00ff) << 8) | \
    7. (((uint_16)(x) & 0xff00) >> 8) \
    8. )
    9. //32位
    10. #define BSWAP_32(x) \
    11. (uint_32)((((uint_32)(x) & 0xff000000) >> 24) | \
    12. (((uint_32)(x) & 0x00ff0000) >> 8) | \
    13. (((uint_32)(x) & 0x0000ff00) << 8) | \
    14. (((uint_32)(x) & 0x000000ff) << 24) \
    15. )
    16. //无符号整型16位
    17. uint_16 bswap_16(uint_16 x)
    18. {
    19. return (((uint_16)(x) & 0x00ff) << 8) | \
    20. (((uint_16)(x) & 0xff00) >> 8) ;
    21. }
    22. //无符号整型32位
    23. uint_32 bswap_32(uint_32 x)
    24. {
    25. return (((uint_32)(x) & 0xff000000) >> 24) | \
    26. (((uint_32)(x) & 0x00ff0000) >> 8) | \
    27. (((uint_32)(x) & 0x0000ff00) << 8) | \
    28. (((uint_32)(x) & 0x000000ff) << 24) ;
    29. }
    30. int main(int argc,char *argv[])
    31. {
    32. printf( "------------带参宏-------------\n");
    33. printf( "%#x\n",BSWAP_16( 0x1234)) ;
    34. printf( "%#x\n",BSWAP_32( 0x12345678));
    35. printf( "------------函数调用-----------\n");
    36. printf( "%#x\n",bswap_16( 0x1234)) ;
    37. printf( "%#x\n",bswap_32( 0x12345678));
    38. return 0 ;
    39. }
    40. 输出结果:
    41. ------------带参宏-------------
    42. 0x3412
    43. 0x78563412
    44. ------------函数调用-----------
    45. 0x3412
    46. 0x78563412

     

    这里有个思考?上面的哪个是转换为大端,哪个是转为小端了呢?

    参看:STM32开发 -- 进制与字符串间的转换

    举个例子,比如数字 0x12 34 56 78在内存中的表示形式为:

    1)大端模式:

    低地址 -----------------> 高地址

    0x12  |  0x34  |  0x56  |  0x78

    2)小端模式:

    低地址 ------------------> 高地址

    0x78  |  0x56  |  0x34  |  0x12

    则:

    转换为大端:

    pPack[2] = (u8)((len >> 8) & 0xFF);
    pPack[3] = (u8)(len & 0xFF);

    转为为小端:

    pPack[2] = (u8)(len & 0xFF);

    pPack[3] =  (u8)((len >> 8) & 0xFF);

     

    第二种方法:

    从软件的角度理解端模式

    使用 htonl, htons, ntohl, ntohs 等函数

    参看:百度百科--htonl ()函数

    参看:百度百科--htons ()函数

     

    查看:man htonl

    
     
    1. NAME
    2. htonl, htons, ntohl, ntohs - convert values between host and network byte order
    3. SYNOPSIS
    4. #include <arpa/inet.h>
    5. uint32_t htonl( uint32_t hostlong);
    6. uint16_t htons( uint16_t hostshort);
    7. uint32_t ntohl( uint32_t netlong);
    8. uint16_t ntohs( uint16_t netshort);
    9. DESCRIPTION
    10. The htonl() function converts the unsigned integer hostlong from host byte order to network byte order.
    11. The htons() function converts the unsigned short integer hostshort from host byte order to network byte order.
    12. The ntohl() function converts the unsigned integer netlong from network byte order to host byte order.
    13. The ntohs() function converts the unsigned short integer netshort from network byte order to host byte order.
    14. On the i386 the host byte order is Least Significant Byte first, whereas the network byte order, as used on the Internet, is Most
    15. Significant Byte first.

    翻译:

    htonl()     //32位无符号整型的主机字节顺序到网络字节顺序的转换(小端->>大端)
    htons()
        //16位无符号短整型的主机字节顺序到网络字节顺序的转换  (小端->>大端)
    ntohl()     //32位无符号整型的网络字节顺序到主机字节顺序的转换  (大端->>小端)
    ntohs()     //16位无符号短整型的网络字节顺序到主机字节顺序的转换  (大端->>小端)

    注,主机字节顺序,X86一般多为小端(little-endian),网络字节顺序,即大端(big-endian);

     

    举两个小例子:

    
     
    1. //示例一
    2. #include <stdio.h>
    3. #icnlude <arpa/inet.h>
    4. int main (void)
    5. {
    6. union
    7. {
    8. short i;
    9. char a[ 2];
    10. }u;
    11. u.a[ 0] = 0x11;
    12. u.a[ 1] = 0x22;
    13. printf ( "0x%x\n", u.i); //0x2211 为小端 0x1122 为大端
    14. printf ( "0x%.x\n", htons (u.i)); //大小端转换
    15. return 0;
    16. }
    17. 输出结果:
    18. 0x2211
    19. 0x1122
    
     
    1. //示例二
    2. #include <stdio.h>
    3. #include <arpa/inet.h>
    4. struct ST{
    5. short val1;
    6. short val2;
    7. };
    8. union U{
    9. int val;
    10. struct ST st;
    11. };
    12. int main(void)
    13. {
    14. int a = 0;
    15. union U u1, u2;
    16. a = 0x12345678;
    17. u1.val = a;
    18. printf( "u1.val is 0x%x\n", u1.val);
    19. printf( "val1 is 0x%x\n", u1.st.val1);
    20. printf( "val2 is 0x%x\n", u1.st.val2);
    21. printf( "after first convert is: 0x%x\n", htonl(u1.val));
    22. u2.st.val2 = htons(u1.st.val1);
    23. u2.st.val1 = htons(u1.st.val2);
    24. printf( "after second convert is: 0x%x\n", u2.val);
    25. return 0;
    26. }
    27. 输出结果:
    28. u1.val is 0x12345678
    29. val1 is 0x5678
    30. val2 is 0x1234
    31. after first convert is: 0x78563412
    32. after second convert is: 0x78563412

     

    在对普通文件进行处理也需要考虑端模式问题。在大端模式的处理器下对文件的32,16位读写操作所得到的结果与小端模式的处理器不同。单纯从软件的角度理解上远远不能真正理解大小端模式的区别。事实上,真正的理解大小端模式的区别,必须要从系统的角度,从指令集,寄存器和数据总线上深入理解,大小端模式的区别。

     

    以下内容了解:

    1、从系统的角度理解端模式

    先补充两个关键词,MSB和LSB:
      MSB:MoST Significant Bit ------- 最高有效位
            LSB:Least Significant Bit ------- 最低有效位

            处理器在硬件上由于端模式问题在设计中有所不同。从系统的角度上看,端模式问题对软件和硬件的设计带来了不同的影响,当一个处理器系统中大小端模式同时存在时,必须要对这些不同端模式的访问进行特殊的处理。
           PowerPC处理器主导网络市场,可以说绝大多数的通信设备都使用PowerPC处理器进行协议处理和其他控制信息的处理,这也可能也是在网络上的绝大多数协议都采用大端编址方式的原因。因此在有关网络协议的软件设计中,使用小端方式的处理器需要在软件中处理端模式的转变。而Pentium主导个人机市场,因此多数用于个人机的外设都采用小端模式,包括一些在网络设备中使用的PCI总线,Flash等设备,这也要求在硬件设计中注意端模式的转换。
           本文提到的小端外设是指这种外设中的寄存器以小端方式进行存储,如PCI设备的配置空间,NOR FLASH中的寄存器等等。对于有些设备,如DDR颗粒,没有以小端方式存储的寄存器,因此从逻辑上讲并不需要对端模式进行转换。在设计中,只需要将双方数据总线进行一一对应的互连,而不需要进行数据总线的转换。
           如果从实际应用的角度说,采用小端模式的处理器需要在软件中处理端模式的转换,因为采用小端模式的处理器在与小端外设互连时,不需要任何转换。而采用大端模式的处理器需要在硬件设计时处理端模式的转换。大端模式处理器需要在寄存器,指令集,数据总线及数据总线与小端外设的连接等等多个方面进行处理,以解决与小端外设连接时的端模式转换问题。在寄存器和数据总线的位序定义上,基于大小端模式的处理器有所不同。
           一个采用大端模式的32位处理器,如基于E500内核的MPC8541,将其寄存器的最高位msb(most significant bit)定义为0,最低位lsb(lease significant bit)定义为31;而小端模式的32位处理器,将其寄存器的最高位定义为31,低位地址定义为0。与此向对应,采用大端模式的32位处理器数据总线的最高位为0,最高位为31;采用小端模式的32位处理器的数据总线的最高位为31,最低位为0。         
           大小端模式处理器外部总线的位序也遵循着同样的规律,根据所采用的数据总线是32位,16位和8位,大小端处理器外部总线的位序有所不同。大端模式下32位数据总线的msb是第0位,MSB是数据总线的第0~7的字段;而lsb是第31位,LSB是第24~31字段。小端模式下32位总线的msb是第31位,MSB是数据总线的第31~24位,lsb是第0位,LSB是7~0字段。大端模式下16位数据总线的msb是第0位,MSB是数据总线的第0~7的字段;而lsb是第15位,LSB是第8~15字段。小端模式下16位总线的msb是第15位,MSB是数据总线的第15~7位,lsb是第0位,LSB是7~0字段。大端模式下8位数据总线的msb是第0位,MSB是数据总线的第0~7的字段;而lsb是第7位,LSB是第0~7字段。小端模式下8位总线的msb是第7位,MSB是数据总线的第7~0位,lsb是第0位,LSB是7~0字段。
             由上分析,我们可以得知对于8位,16位和32位宽度的数据总线,采用大端模式时数据总线的msb和MSB的位置都不会发生变化,而采用小端模式时数据总线的lsb和LSB位置也不会发生变化。
             为此,大端模式的处理器对8位,16位和32位的内存访问(包括外设的访问)一般都包含第0~7字段,即MSB。小端模式的处理器对8位,16位和32位的内存访问都包含第7~0位,小端方式的第7~0字段,即LSB。由于大小端处理器的数据总线其8位,16位和32位宽度的数据总线的定义不同,因此需要分别进行讨论在系统级别上如何处理端模式转换。在一个大端处理器系统中,需要处理大端处理器对小端外设的访问。

    2、实际中的例子


           虽然很多时候,字节序的工作已由编译器完成了,但是在一些小的细节上,仍然需要去仔细揣摩考虑,尤其是在以太网通讯、MODBUS通讯、软件移植性方面。这里,举一个MODBUS通讯的例子。在MODBUS中,数据需要组织成数据报文,该报文中的数据都是大端模式,即低地址存高位,高地址存低位。假设有一16位缓冲区m_RegMW[256],因为是在x86平台上,所以内存中的数据为小端模式:m_RegMW[0].low、m_RegMW[0].high、m_RegMW[1].low、m_RegMW[1].high……
    为了方便讨论,假设m_RegMW[0] = 0x3456; 在内存中为0x56、0x34。
           现要将该数据发出,如果不进行数据转换直接发送,此时发送的数据为0x56,0x34。而Modbus是大端的,会将该数据解释为0x5634而非原数据0x3456,此时就会发生灾难性的错误。所以,在此之前,需要将小端数据转换成大端的,即进行高字节和低字节的交换,此时可以调用步骤五中的函数BigtoLittle16(m_RegMW[0]),之后再进行发送才可以得到正确的数据。

     

    展开全文
  • 什么是大小端?如何确定大小端

    万次阅读 多人点赞 2019-08-25 19:59:40
    一、什么是大小端? 对于一个由2个字节组成的16位整数,在内存中存储这两个字节有两种方法:一种是将低序字节存储在起始地址,这称为小端(little-endian)字节序;另一种方法是将高序字节存储在起始地址,这称为大端...

    一、什么是大小端?

    对于一个由2个字节组成的16位整数,在内存中存储这两个字节有两种方法:一种是将低序字节存储在起始地址,这称为小端(little-endian)字节序;另一种方法是将高序字节存储在起始地址,这称为大端(big-endian)字节序。

    假如现有一32位int型数0x12345678,那么其MSB(Most Significant Byte,最高有效字节)为0x12,其LSB (Least Significant Byte,最低有效字节)为0x78,在CPU内存中有两种存放方式:(假设从地址0x4000开始存放)

    总结:

    大端是高字节存放到内存的低地址

    小端是高字节存放到内存的高地址

    二、如何确定大小端

    有些CPU公司用大端(譬如C51单片机);有些CPU用小端(譬如ARM)。(大部分是用小端模式,大端模式的不算多)。于是乎我们写代码时,当不知道当前环境是用大端模式还是小端模式时就需要用代码来检测当前系统的大小端。下面给出用程序判断大小端的两种方法:

    #include <stdio.h>
    
    // 共用体中很重要的一点:a和b都是从u1的低地址开始存放的。
    // 假设u1所在的4字节地址分别是:0、1、2、3的话,那么a自然就是0、1、2、3;
    // b所在的地址是0而不是3.
    
    union myunion
    {
    	int a;
    	char b;
    };
    
    // 如果是小端模式则返回1,小端模式则返回0
    int is_little_endian(void)
    {
    	union myunion u1;
    	u1.a = 0x12345678;				// 地址0的那个字节内是0x78(小端)或者0x12(大端)
        if(0x78 == u1.b)
            return 1;
        else if(0x12 == u1.b)
    	    return 0;
    }
    
    int is_little_endian2(void)
    {
    	int a = 0x12345678;
    	char b = *((char *)(&a));		// 指针方式其实就是共用体的本质
    	if(0x78 == b)
            return 1;
        else if(0x12 == b)
    	    return 0;
    }
    
    
    int main(void)
    {
    	int i = is_little_endian2();
    	//int i = is_little_endian();
    	if (i == 1)
    	{
    		printf("小端模式\n");
    	}
    	else
    	{
    		printf("大端模式\n");
    	}
    	
    	return 0;
    }

    下面给出三种确定大小端错误的方案

    	// 强制类型转换
    int a;
    char b;
    a = 1;
    b = (char)a;
    printf("b = %d.\n", b);
    	// 移位
    int a, b;
    a = 1;
    b = a >> 1;
    printf("b = %d.\n", b);
    	// 位与
    int a = 1;
    int b = a & 0xff;		// 也可以写成:char b = a & 0x01;
    printf("b = %d.\n", b);

    位与、移位、强制类型转换等运算是编译器提供的运算,这个运算是高于内存层次的(或者说这些运算在二进制层次具有可移植性,也就是说&的时候一定是高字节&高字节,低字节&低字节,和二进制存储无关)。

     

    REF:

    朱有鹏课堂笔记

    展开全文
  • 目录什么是大小端模式为什么会有大小端模式之分什么情况需要考虑大小端模式常见的设备的大小端模式测试大小端模式例程 什么是大小端模式 大端模式Big-Endian:高字节存于内存低地址,低字节存于内存高地址。 小端...

    1. 什么是大小端模式

    大端模式Big-Endian:高字节存于内存低地址,低字节存于内存高地址。
    小端模式Little-Endian:低字节存于内存低地址,高字节存于内存高地址。

    网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。

    首先我们来看下数据在大小端两种模式下存储图,假设有一个整型数0x12345678,从图中可以看出明显的区别:
    在这里插入图片描述
    再给一张图便于理解:
    在这里插入图片描述

    2. 为什么会有大小端模式之分

    这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于 8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于 大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。

    关于为什么会有大小端模式之分还可以从大小端两种模式各自的优缺点来分析:
    Big-Endian优点:靠首先提取高位字节,你总是可以由看看在偏移位置为0的字节来确定这个数字是 正数还是负数。你不必知道这个数值有多长,或者你也不必过一些字节来看这个数值是否含有符号位。这个数值是以它们被打印出来的顺序存放的,所以从二进制到 十进制的函数特别有效。
    因而,对于不同要求的机器,在设计存取方式时就会不同。

    Little-Endian优点:提取一个,两个,四个或者更长字节数据的汇编指令以与其他所有格式相同的方式进行:首先在偏移地址为0的地方提取最低位的字节,因为地址偏移和字节数是一对一的关系,多重精度的数学函数就相对地容易写了。
    如果你增加数字的值,你可能在左边增加数字(高位非指数函数需要更多的数字)。 因此, 经常需要增加两位数字并移动存储器里所有Big-endian顺序的数字,把所有数向右移,这会增加计算机的工作量。不过,使用Little- Endian的存储器中不重要的字节可以存在它原来的位置,新的数可以存在它的右边的高位地址里。
    这就意味着计算机中的某些计算可以变得更加简单和快速。

    3. 什么情况需要考虑大小端模式

    相同字节序的平台在进行网络通信时可以不进行字节序转换,但是跨平台进行网络数据通信时必须进行字节序转换。

    原因如下:网络协议规定接收到得第一个字节是高字节,存放到低地址,所以发送时会首先去低地址取数据的高字节。小端模式的多字节数据在存放时,低地址存放的是低字节,而被发送方网络协议函数发送时会首先去低地址取数据(想要取高字节,真正取得是低字节),接收方网络协议函数接收时会将接收到的第一个字节存放到低地址(想要接收高字节,真正接收的是低字节),所以最后双方都正确的收发了数据。

    而相同平台进行通信时,如果双方都进行转换最后虽然能够正确收发数据,但是所做的转换是没有意义的,造成资源的浪费。而不同平台进行通信时必须进行转换,不转换会造成错误的收发数据,字节序转换函数会根据当前平台的存储模式做出相应正确的转换,如果当前平台是大端,则直接返回不进行转换,如果当前平台是小端,会将接收到得网络字节序进行转换。

    4. 常见的设备的大小端模式

    STM32单片机:小端模式
    STM8:大端
    KEIL C51:大端
    x86:小端
    ARM既可以工作在大端模式,也可以工作在小端模式

    注意:大小端模式是和硬件有关的,即和芯片本身有关,IDE不能进行设置。

    5. 测试大小端模式例程

    //如果字节序为big-endian,返回true;
    //反之为   little-endian,返回false
    
    bool IsBig_Endian()
    {
        unsigned short test = 0x1234;
        if(*( (unsigned char*) &test ) == 0x12)
           return TRUE;
       else
           return FALSE;
    }//IsBig_Endian()
    

    其他例程:

    int checkCPUendian()
    {
          union{
                 unsigned long int i;
                 unsigned char s[4];
           }c;
           c.i = 0x12345678;
           return (0x12 == c.s[0]); 
    }
    

    6. 大小端转化例程

    typedef unsigned short int uint16;
    typedef unsigned long int uint32;
    // 短整型大小端互换
    #define BigLittleSwap16(A)  ((((uint16)(A) & 0xff00) >> 8) | \
     
                                 (((uint16)(A) & 0x00ff) << 8))
     
     // 长整型大小端互换
    #define BigLittleSwap32(A)  ((((uint32)(A) & 0xff000000) >> 24) | \
    
                                 (((uint32)(A) & 0x00ff0000) >> 8) | \
     
                                (((uint32)(A) & 0x0000ff00) << 8) | \
     
                                (((uint32)(A) & 0x000000ff) << 24))
    

    参考:
    https://blog.csdn.net/weixin_34088583/article/details/94191143
    https://blog.csdn.net/dongfangjing/article/details/50822143
    https://strongerhuang.blog.csdn.net/article/details/99669954

    展开全文
  • 计算机大小端以及大小端查看

    千次阅读 2019-05-26 12:59:27
    数据在计算机中存储的时候,分为大端存储和小端存储,每个计算机的大小端存储都不同,为了了解自己的机器中的大小端类型,可以通过很多方法查看。这里我们主要讲解两种查看大小端的方法。 那么到底什么是大小端呢?...
  • 概述 本篇文章介绍如何使用STM32HAL库,USART-调试串口(大小端测试)示例。 硬件:STM32F103CBT6最小系统板 软件:Keil 5.29 + STM32CubeMX6.01 一、原理 CPU的大端和小端模式很多地方都会用到,由于不同硬件商,...
  • 大小端模式

    千次阅读 2019-05-25 16:32:52
    大端模式,是指数据的高... 小模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。 中...
  • 总述: ...对于大小端的几个结论: ...1.char型变量和char型数组没有大小端的区分。 2.需要转化数据类型大于1个字节的数据类型:short,int,枚举,联合体等。 一.为什么要进行...
  • Linux 大小端转换函数

    千次阅读 2019-10-14 16:37:31
    PC 存储多字节值是低字节为先(小为先, 因此是小), 一些高级的平台以另一种方式(大端)工作. 任何可能的时候, 你的代码应当这样来编写, 它不在乎它操作的数据的字节序. 但是, 有时候一个驱动需要使用单个字节建立...
  • Linux一句命令之判断大小端

    千次阅读 2018-12-28 09:41:46
    笔者在开发Linux应用程序时,由于判断大小端序的问题,使用的方法是用C语言判断,方法是可以判断得到系统是什么端序,但是太麻烦了。笔者是比较懒的人,不想写那么多代码,想一句命令就解决端序判断的问题。 想了想...
  • 正确区分大小端模式

    千次阅读 2020-03-18 15:38:52
    正确区分大小端模式 嵌入式开发经常会遇到大小端的问题,往往学习后,过一段时间就又忘记了,这里总结一下,希望给大家留下深刻的记忆。 字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端...
  • 如何判断大小端

    千次阅读 2020-07-27 08:19:49
    如何判断大小端 1.大小端的概念 大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中 小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 615,080
精华内容 246,032
关键字:

大小端