C语言-大小端序的详解

Python011

C语言-大小端序的详解,第1张

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

0x12 | 0x34 | 0x56 | 0x78

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

0x78 | 0x56 | 0x34 | 0x12

高地址

-----------

buf[3] (0x78) ->低位

buf[2] (0x56)

buf[1] (0x34)

buf[0] (0x12) ->高位

-----------

低地址

高地址

-----------

buf[3] (0x12) ->低位

buf[2] (0x34)

buf[1] (0x56)

buf[0] (0x78) ->高位

-----------

低地址

先看下面的代码,然后我在简短的解释一下。

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <string>#define nmemb 7/****************************************************

 Date types(Compiler specific) 数据类型(和编译器相关)

*****************************************************/typedef unsigned char uint8     /* Unsigned 8 bit quantity  */typedef signed char int8        /* Signed 8 bit quantity    */typedef unsigned short uint16   /* Unsigned 16 bit quantity */typedef signed short int16      /* Signed 16 bit quantity   */typedef unsigned int uint32     /* Unsigned 32 bit quantity */typedef signed int int32        /* Signed 32 bit quantity   */typedef float fp32              /* Single precision         */

                                 /* floating point           */typedef double fp64             /* Double precision         */

                                 /* floating point           *///int32#define BigtoLittle32(A)   ((( (uint32)(A) &0xff000000 ) >>24) | \

                                              (( (uint32)(A) &0x00ff0000 ) >>8)   | \

                                              (( (uint32)(A) &0x0000ff00 ) <<8)   | \

                                              (( (uint32)(A) &0x000000ff ) <<24))//int16#define BigtoLittle16(A)   (( ((uint16)(A) &0xff00) >>8 )    | \

                           (( (uint16)(A) &0x00ff ) <<8))/************************************************************

*     Conversion little endian float data to big endian

*     *************************************************************/float ReverseFloat(const float inFloat)

{    float retVal   char *floatToConvert = (char*) &inFloat   char *returnFloat = (char*) &retVal   // swap the bytes into a temporary buffer

   returnFloat[0] = floatToConvert[3]

   returnFloat[1] = floatToConvert[2]

   returnFloat[2] = floatToConvert[1]

   returnFloat[3] = floatToConvert[0]   return retVal

}struct matrix

{    int row   int column

}s[nmemb]void set_s(int j, int x, int y)

{

   s[j].row = x

   s[j].column = y

}bool is_bigendian()

{    int a = 0x1234   char b =  *(char *)&a //b == the Low address part of a

   //printf("%c\n", b)

   if (b == 0x34) {        return false

   }    return true

}int main()

{    if (is_bigendian()) {        printf("BigEndian\n")

   } else {        printf("LittleEndian\n")

   }

   FILE *fp

   set_s(0, 1, 50)

   set_s(1, 1, 80)

   set_s(2, 4, 20)

   set_s(3, 50, 1)

   set_s(4, 80, 2)

   set_s(5, 100, 3)

   set_s(6, 100, 4)   int ans = sizeof(struct matrix)   printf("size: %d\n", ans)   printf("size: %d\n", sizeof(s))   if ((fp = fopen("test", "wb")) == NULL) {        printf("EROOR\n")       return 1

   }    for (int j = 0j <nmemb++j) {        printf("row: %d   column: %d\n", s[j].row, s[j].column)

   }

   fwrite(s, sizeof(struct matrix), nmemb, fp)   for (int i = 0i <nmemb++i) {        float *m = (float*) malloc(sizeof(float) * s[i].row * s[i].column)

       bzero(m, sizeof(float) * s[i].row * s[i].column)       for (int j = 0j <s[i].row++j) {            for (int k = 0k <s[i].column++k) {

               m[k + j*s[i].column] = k

           }

       }

       fwrite(m, sizeof(float), s[i].row * s[i].column, fp)       free(m)

   }

   fclose(fp)   printf("11\n")   /*

   printf("%d\n", sizeof(float))

   FILE *fp

   if ((fp = fopen("test", "rb")) == NULL) {

       printf("EROOR\n")

       return 1

   }

   fread(s, sizeof(struct matrix), nmemb, fp)

   for (int i = 0i <nmemb++i) {

       printf("row: %d   column: %d\n", s[i].row, s[i].column)

   }

   for (int i = 0i <nmemb++i) {

       float *m = (float*) malloc(sizeof(float) * s[i].row * s[i].column)

       bzero(m, sizeof(float) * s[i].row * s[i].column)

       fread(m, sizeof(float), s[i].row * s[i].column, fp)

       for (int j = 0j <s[i].row++j) {

           for (int k = 0k <s[i].column++k) {

               printf("%lf ", m[k + j*s[i].column])

           }

           printf("\n")

       }

       printf("\n\n")

       free(m)

   }

   fclose(fp)

   */

   return 0

}

fopen和fclose是很常见的,在这里就不做解释了。我们来看看fwrite和fread,本来以为这个很麻烦,但是用过之后发现这个二进制文件读写才是最简单的。

size_t fwrite(const void * ptr,size_t size,size_t nmemb,FILE * stream)

fwrite()用来将数据写入文件流中。

stream为已打开的文件指针

ptr 指向欲写入的数据地址

写入的字符数以参数size*nmemb来决定。

size表示写入一个nmemb的内存大小。

fwrite()会返回实际写入的nmemb数目。

size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)

fread()用来从文件流中读取数据。

stream为已打开的文件指针

ptr 指向欲存放读取进来的数据空间

读取的字符数以参数size*nmemb来决定

size表示读取一个nmemb的内存大小。

fread()会返回实际读取到的nmemb数目,如果此值比参数nmemb 小,则代表可能读到了文件尾或有错误发生,这时必须用feof()或ferror()来决定发生什么情况。

返回实际读取到的nmemb数目。

详情参见上面的代码。

另外就是大小端的问题了。关于大小端的具体解释网上有很多,在此不作解释。参考上面写的代码,我判断了自己机器是大端还是小端,并且实现了int16,int32已经float数据类型的大小端转换,大端转小端,在使用相同的代码一次小端又变成了大端。

PS:float的大小端转化我之前一直以为写的是错的,因为好多数据转化之后输出都是0。后来发现可能是与float类型在内存中的存放有关,我们的程序是对的。

在计算机系统中,存储是以字节为单位的,每个地址单元都对应着一个字节,一个字节=8bit。在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器)。对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,如何安排多个字节的存储,这就有了大端存储模式和小端存储模式。

小端:较高的有效字节存放在较高的的存储器地址,较低的有效字节存放在较低的存储器地址。

大端:较高的有效字节存放在较低的存储器地址,较低的有效字节存放在较高的存储器地址。

如果将一个16位的整数0x1234存放到一个短整型变量(short)中。这个短整型变量在内存中的存储在大小端模式由下表所示。

C语言判断大小端模式

方法一:

voidIsBigEndian()

{

    shortinta=0x1122//十六进制,一个数值占4位charb =  *(char*)&a//通过将short(2字节)强制类型转换成char单字节,b指向a的起始字节(低字节)

    if( b ==0x11) //低字节存的是数据的高字节数据

    {

        //是大端模式

    }

    else

    {

        //是小端模式

    }

}

方法二:

voidIsBigEndian() //原理:联合体union的存放顺序是所有成员都从低地址开始存放,而且所有成员共享存储空间

{

    uniontemp

    {

        shortint a

        char b

    }temp

    temp.a=0x1234

    if(temp.b==0x12) //低字节存的是数据的高字节数据

    {

        //是大端模式

    }

    else

    {

        //是小端模式

    }

}

参考:https://www.jianshu.com/p/152268b0ea19