C语言大小端问题

C语言 专栏收录该内容
13 篇文章 1 订阅

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
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:1024 设计师:我叫白小胖 返回首页

打赏作者

以前吃不胖丶

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值