C语言大小端问题
一、概念
大端存储:一个数的低位字节序的内容存放到高地址处,高位字节序的内容存放在低地址处。
小端存储:一个数的低位字节序的内容存放到低地址处,高位字节序的内容存放在高地址处。
举个例子:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int a = 1;
char *p = &a;
int i = 0;
for(i = 0; i < sizeof(a); i++)
{
printf("[%p][%d][%#x]\n",p, i, *p++);
}
//printf("%s \n", isBigEndian() ? "big" : "small");
return 0;
以上代码中,声明了一个int型变量a,占4个字节,打印的结果为:
[0x7ffec1d68aa1][0][0x1]
[0x7ffec1d68aa2][1][0]
[0x7ffec1d68aa3][2][0]
[0x7ffec1d68aa4][3][0]
a的值是1 ,在内存中存储应该是0x 00 00 00 01才对啊,为什么编译器给出的却是0x 01 00 00 00?
因为运行该代码的计算机是小端模式,即数据的低位字节存放在低地址。一般常用的设备大多都是小端模式。
二、判断方法
根据以上知识,可以利用数据低地址的数据判断设备的大小端模式
char isBigEndian()
{
unsigned int dwVal=0x1234;
if(*((unsigned char *)&dwVal) == 0x12)
{
return 1;
}
else
{
return 0;
}
}
先初始化一个unsigned int 类型的变量dwVal,dwVal占用四个字节,再用unsigned char强转,此时的强转会截取dwVal的最低地址的那个字节。若低地址存储的是12,说明低地址存放高字节,即大端模式,反之低地址存放低字节34,即小端模式。
三、相关问题
在数据通信过程中,数据存储在char型数组中,若想把数据转为int型,需要确定保存在char型数组中的顺序是否为小端模式,若不是小端模式,可通过位操作转为小端,只有小端模式,才能使用memcpy4字节到int型数据的地址,如下
int nVal;
char c[4];
memset(c,0,4);
c[0]=0x12;
c[1]=0x34;
c[2]=0x56;
c[3]=0x78;
//转为int后从高地址到低地址 0x78 0x56 0x34 0x12
memcpy(&nVal,c,4);//nVal = 2018915346
再记一个无关的问题,int与float类型强转会出现精度丢失,今天尝试float直接强转为int,个位数出现偏差。查阅网上资料表明,一般浮点与整型的强转用double。在64位计算机上,我是用long强转了double后,再赋值给了int,数据显示正常。
2021年1月16日更新
在使用char数组往short数组拷贝数据时候发现一个问题,short数组中的数据高低字节交换了,这里面还是涉及到了内存地址与数据高低字节问题。假设char数组在内存中由低地址到高地址的存放顺序为:
0x1 0x2 0x3 0x4 0x5 0x6
然后把这6个字节直接拷贝到short数组中,在short数组中,数据存放还是这个顺序:
0x1 0x2 0x3 0x4 0x5 0x6
但是,当把数据按short型读取出来时,就不一样了,假设short数组为awVal,每个short类型数据占2个字节,所以对应awVal数组在内存中的数据就是:
awVal[0]:0x1 0x2
awVal[1]:0x3 0x4
awVal[2]:0x5 0x6
以awVal[0]举例,以short类型读取后,因为是小端设备,数据的低字节存放在低地址,高字节存放在高地址,所以awVal[0]的值为0x201,这也就解释了高低字节交换的现象。可以通过下代码证实高低字节交换问题,若实际应用需要把char型数组数据拷贝到shrot型,可提前进行高低字节交换后再拷贝;若是拷贝到int型数组,则需要先交换高低字,再交换高低字节。
#include <stdio.h>
#include <string.h>
int main()
{
char *p = NULL;
unsigned short awVal[4] = {0};
char achVal[] = {1,2,3,4,5,6};
int i;
printf("\nachVal:\n");
for (i = 0; i < sizeof(achVal); i++)
{
printf(" %#x", achVal[i]);
}
memcpy(awVal, achVal, sizeof(achVal));
p = (char *)awVal;
printf("\np:\n");
for (i = 0; i < sizeof(achVal); i++)
{
printf(" %#x", p[i]);
}
printf("\nawVal:\n");
for (i = 0; i < 4; i++)
{
printf(" %#x", awVal[i]);
}
printf("\n\n");
return 0;
}
打印结果为:
achVal:
0x1 0x2 0x3 0x4 0x5 0x6
p:
0x1 0x2 0x3 0x4 0x5 0x6
awVal:
0x201 0x403 0x605 0