• 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
    // **********************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
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108

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

    3. 影响

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

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

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

  • 相关阅读:
    跨平台的桌面应用开发,技术框架选择
    [硬件基础]-快速了解I2C串行通信协议
    NodeJS 实战系列:DevOps 尚未解决的问题
    Git获取本地仓库及基本操作指令
    C++之哈希表、哈希桶的实现
    【AFL学习笔记(一)】简单的使用AFL进行漏洞挖掘测试
    android 编译make指令
    jscpd对项目进行查重(支持150+类语言)
    鸿蒙原生应用/元服务开发-AGC分发如何编译打包应用
    【老生谈算法】matlab实现分形树源码——分形树
  • 原文地址:https://blog.csdn.net/wangjunliang/article/details/126760660