C++ | 大小端模式的概念、检测与影响

1. 基本概念

(1) 数据类型与存储

  • 8bits = 1byte, 一个字节,就是一个char,2**8=256,最高位不用是 128;
  • 8bits(比特位 / 位) = 1byte(字节);
  • 16进制需要 1 2 4 8 2^4=16,4位二进制01(bits)来表示,也就是半字节。
  • 一个char 占用 1 bytes,正好需要2位16进制来表示。对应颜色的 (10)255 = (16)FF;
    • 大小端都要保证一个char是完整的。
  • 一个 int 占用 4 bytes,需要 8 个16进制位来表示。
    • 0x12345678; 把int写成16进制,每2位都是一个bytes,是内存的直接状态: 0x12 0x34 0x56 0x78

(2) 高位(MSB) /低位(LSB)

比如 int i = 0x12345678;

  • 高位/影响最大的位 most significant bit: 12 相当于万位
  • 低位/影响最小的位 least significant bit: 78 相当于个位

对于一个很大的数字,高位变化1,影响很大;低位变化1,基本没啥影响。

(3) 内存高低地址

可以打印出地址比较大小。
高低是一个相对量。
比如,0x01 和 0x 02 比较,前置就是低地址,后者是高地址。

(3) 大小端

字节(2个16进制位)是大小端的基本单位。
字节内部没有大小端区分。
不同变量之间也没有大小端的概念。

只有一个变量内部,在内存中表示时,才牵涉到高位放在高地址还是低地址的问题。这是CPU决定的。

  • 基于分层的概念,数值读写一般不需要关注存储细节,除非有强制类型转换。
  • 读取肯定要和最初的写入一致,要读出 0x12345678。
  • 在内存中:
    • 大端(低地址 放高位/万位) |0x12|0x34|0x56|0x78|----| 低地址 -----> 高地址
    • 小端(低地址 放低位/个位) |----|0x78|0x56|0x34|0x12| 低地址 -----> 高地址
  • 优劣:
    • 大端模式比较符合人的直观习惯: 大端就像我们手写一串数字,先写百位,再写十位,再写个位,依次放到内存中:地址由小向大增加,而数据从高位往低位放
    • 但小端模式是intel的选择。更符合逻辑: 低地址的不重要(least significant bit),高地址的重要(most significant bit)。

(4) 读取时:

  • 1)大端依次读出,小端倒叙读出。读取时,字节内部是一个整体不受倒叙影响。
  • 2)读取后,就和之前未存储时顺序一致了,也就是数没发生变化。

2. 检测方法

#include<iostream>
// **********************1
void test1(){
	short int x;
	char x0,x1;
	x=0x1122;
	
	x0=((char*)&x)[0]; //低地址单元
	x1=((char*)&x)[1]; //高地址单元
	printf("x0=%d,%c\t x1=%d,%c \n", x0,x0, x1,x1); //34 17
	// 低地址存的是低位(22 相当于是个位 Least significant end),小端
}




// **********************2
// 共用体检测
union myunion{
	int a;
	char b;
};

int isLittleU(){
	union myunion s1;  //共用体测试
	
	s1.a=0x10000000;
	if(s1.b==0x10){
		return 0; //big
	}else if(s1.b==0x00){
		return 1; //little
	}

	return -1;
}

//指针检测
int isLittleP(){
	int a;
	a=0x10000001;   //指针测试
	char b=*((char*)(&a));
	//printf(">> b=%d\n", b);

	if(b==0x10){
		return 0;	//printf("Big\n");
	}else if(b==0x01){
		return 1;	//printf("little\n"); 
	}

	return -1;
}

void test2(){
	//代码对,分析错的博客: https://www.jianshu.com/p/47dc814c9146
	// 分析合理: https://blog.csdn.net/a6333230/article/details/117117919 
	std::cout << "is little?   union method: " << isLittleU() << std::endl;
	std::cout << "is little? pointer method: " << isLittleP() << std::endl;
	std::cout << std::endl;
}



// **********************3
void test3(){
	// https://blog.csdn.net/wwwlyj123321/article/details/100066463
	//int hexInt=0x01020306;
	int hexInt=0x41426162; //ABab ->10进制 65 66 97 98 ->16进制 41 42 61 62
	//获取int的地址,转为指向char的指针
	char *p2=(char*) &hexInt;     // 指针方式其实就是共用体的本质
	printf("hexInt=%x\n", hexInt);
	printf("length, char*: %d, char: %d, int: %d\n", sizeof(p2), sizeof(*p2), sizeof(int));
	
	printf("\n\n");
	for(int i=0; i<4; i++){
		// 逐个打印char,不行 %c
		// 逐个打印 int,可以?
		printf("[%d](%p) %d %c\n",i, ( p2 +i), *( p2 +i),  *( p2 +i) );
	}
}

int main(int argc, char *argv[]){
	void printAscii(int colNumber);
	// 直接打印,int to char 失败。有人说不能强制转换,要使用指针。
	test1();
	test2();
	test3();

	//part2: 如果有额外参数,则打印ascii 码
	if(argc>1){
		// 打印参数列表
		printf("\n>>argc:%d\n", argc);
		for(int i=0; i<argc; i++){
			printf("argv[%d]=%s\n", i, argv[i]);
		}
		printAscii(9);
	}
	return 0;
}

//打印 ascii 码: 按 128*2 打印,虽然128后面大多是空的
void printAscii(int colNumber){
	for(int i=0; i<255; i++){
		printf("[%d]%c\t", i, i);
		if(i%colNumber==0){
			printf("\n");
		}
	}
}

$ g++ -std=c++11 a11.cpp
输出:
在这里插入图片描述

3. 影响

搞明白了,我确实不需要花时间搞懂这个大小端。

只有非8bits机器,或者网络字节流需要考虑

数值计算,只需要知道c++数据类型、函数、传参、引用、指针、特别是高维指针、返回、文件IO这个子集就可以了,需要改写了还要知道class等。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值