当前位置: 首页 > web >正文

【208】VS2022 C++ 32位整数和unsigned char数组之间互相转换

一、场景

在实际应用中,特别是在数据传输的时候,需要读取unsigned char数组,再转换成 32 位整数;或者把 32 位整数转换成 unsigned char数组进行写入。比如对接西门子PLC的 snap7 就是这样。32 位整数分成有符号的无符号的,我们分开讨论。

二、有符号的 32 位整数

2.1 补码的原理

原码:最高位0表示正数,1表示负数。其他位就是用二进制表示数字。

反码:正整数反码和原码相同。负整数原码最高位不变;其他位 0 变 1,1 变 0;最终结果就是负整数的反码。

补码:正整数的补码和原码相同。负整数的补码是它的反码加一。

怎么把补码转换为原码?只要对补码再做一次补码操作就行。

计算机的整数是用补码储存的。这样做的好处是用加法运算替代减法运算。任何加减运算只需要让两个数字的补码相加就行了。

我可以利用这个特性,做到 unsigned char 数组和有符号32位整数互相转换。

2.2 有符号32位整数转换成 unsigned char 数组

执行代码

int a = -1550458175;
unsigned char c = a;

这段代码中,unsigned char 类型的变量 c 是存放了 int 类型变量 a 的低 8 位二进制补码。利用这个特点,对 int 类型的变量 a 分别不右移、右移 8 位、右移 16 位、右移 24 位,然后分别赋值给四个 unsigned char 类型的变量,那么这四个变量可以获取从低到高 4 个字节(1 字节等于 8 位)的补码数据。具体实现方式建议读者看后面 int ucharArrToInt(const unsigned char* const inArr, const int inArrSize, const int inStart, int* outResult) 函数。

2.3 unsigned char 数组转换成有符号32位整数

声明四个 int 变量 data_1、data_2、data_3 和 data_4,初始值是 0.
data_1 赋值成 unsigned char 数组第 0 个元素,然后左移 24 位。
data_2 赋值成 unsigned char 数组第 1 个元素,然后左移 16 位。
data_3 赋值成 unsigned char 数组第 2 个元素,然后左移 8 位。
data_4 赋值成 unsigned char 数组第 3 个元素。
data_1、data_2、data_3 和 data_4 四个整数相加。
如果原来的整数是正数或者是零,这么干完全没问题。
如果原来的整数是负数呢?其实也没有问题。虽然这种做法会让 data_1 是负数,data_2、data_3、data_4 是正数,但是补码的运算方式是减法当加法运算,这四个 int 类型变量的补码会只在自己对应二进制位置有值,其他的地方都是零。即这四个数字的补码互不影响,最后相加的结果就是原来有符号 32 位整数的补码。

下面是测试的代码

#include <stdio.h>
#include <stdlib.h>
#include <random>#define ARR_SIZE 256// 把有符号32位整数转换成 unsigned char 数组
// inNum 输入参数,要转换的有符号32位整数
// inArrSize 输入参数,输出参数outArr的长度
// inStart 输入参数,输出参数outArr 从第几个元素开始写入转换后的数据。
// outArr 输出参数,保存转换后的数组内容。
int intToUcharArr(const int inNum, const int inArrSize, const int inStart, unsigned char* const outArr) {if (inArrSize - inStart < 4) {return -1;}outArr[inStart + 3] = inNum;outArr[inStart + 2] = inNum >> 8;outArr[inStart + 1] = inNum >> 16; // 8 * 2outArr[inStart] = inNum >> 24; // 8 * 3return 0;
}// unsigned char 数组转换成有符号32位整数
// inArr 输入参数,unsigned char 数组。
// inArrSize 输入参数,数组inArr的长度。
// inStart 输入参数,表示从哪个 inArr 的元素开始,读取四个元素转换成int
// outResult 输出参数,转换后的结果
// 返回:0表示正常,其他值表示出错。
int ucharArrToInt(const unsigned char* const inArr, const int inArrSize, const int inStart, int* outResult) {if (inArrSize - inStart < 4) {return -1;}unsigned char c1 = inArr[inStart];unsigned char c2 = inArr[inStart + 1];unsigned char c3 = inArr[inStart + 2];unsigned char c4 = inArr[inStart + 3];int data_1 = 0;int data_2 = 0;int data_3 = 0;int data_4 = 0;data_1 = c1;data_1 = data_1 << 24; // 8 * 3data_2 = c2;data_2 = data_2 << 16; // 8 * 2data_3 = c3;data_3 = data_3 << 8;data_4 = c4;(*outResult) = data_1 + data_2 + data_3 + data_4;return 0;
}// 生成 INT_MIN 到 INT_MAX 随机数,包含 INT_MIN 和 INT_MAX
int genRandom() {// 使用随机设备作为种子std::random_device rd;// 使用 Mersenne Twister 引擎std::mt19937 gen(rd());// 定义分布范围 [0, 255]std::uniform_int_distribution<> distr(INT_MIN, INT_MAX);// 生成并输出随机数int result = distr(gen);return result;
}int main(int argc, char** argv) {system("color 02");printf("argc=%d\n", argc);int ret = -1;// 生成随机数int num = genRandom();//int num = INT_MIN;printf("num = %d\n", num);// 先把随机32位整数转换成 unsigned char 数组,再转换回 32 位整数unsigned char arr[ARR_SIZE];ret = intToUcharArr(num, ARR_SIZE, 0, arr);if (0 != ret) {printf("intToUcharArr error. ret=%d\n", ret);return -1;}int n2 = 0;ret = ucharArrToInt(arr, ARR_SIZE, 0, &n2);if (0 != ret) {printf("ucharArrToInt error. ret=%d\n", ret);return -1;}printf("n2  = %d\n", n2);if (num == n2) {printf("true\n");}else {printf("false\n");}return 0;
}

三、无符号的 32 位整数

计算机中正整数的补码和原码相同,无符号32位整数和 unsigned char 数组的转换方式和有符号的一样。只是需要注意需要改成 unsigned int 类型。

#include <stdio.h>
#include <stdlib.h>
#include <random>#define ARR_SIZE 256// 把有符号32位整数转换成 unsigned char 数组
// inNum 输入参数,要转换的有符号32位整数
// inArrSize 输入参数,输出参数outArr的长度
// inStart 输入参数,输出参数outArr 从第几个元素开始写入转换后的数据。
// outArr 输出参数,保存转换后的数组内容。
int intToUcharArr(const unsigned int inNum, const int inArrSize, const int inStart, unsigned char* const outArr) {if (inArrSize - inStart < 4) {return -1;}outArr[inStart + 3] = inNum;outArr[inStart + 2] = inNum >> 8;outArr[inStart + 1] = inNum >> 16; // 8 * 2outArr[inStart] = inNum >> 24; // 8 * 3return 0;
}// unsigned char 数组转换成有符号32位整数
// inArr 输入参数,unsigned char 数组。
// inArrSize 输入参数,数组inArr的长度。
// inStart 输入参数,表示从哪个 inArr 的元素开始,读取四个元素转换成int
// outResult 输出参数,转换后的结果
// 返回:0表示正常,其他值表示出错。
int ucharArrToInt(const unsigned char* const inArr, const int inArrSize, const int inStart, unsigned int* outResult) {if (inArrSize - inStart < 4) {return -1;}unsigned char c1 = inArr[inStart];unsigned char c2 = inArr[inStart + 1];unsigned char c3 = inArr[inStart + 2];unsigned char c4 = inArr[inStart + 3];unsigned int data_1 = 0;unsigned int data_2 = 0;unsigned int data_3 = 0;unsigned int data_4 = 0;data_1 = c1;data_1 = data_1 << 24; // 8 * 3data_2 = c2;data_2 = data_2 << 16; // 8 * 2data_3 = c3;data_3 = data_3 << 8;data_4 = c4;(*outResult) = data_1 + data_2 + data_3 + data_4;return 0;
}// 生成 INT_MIN 到 INT_MAX 随机数,包含 INT_MIN 和 INT_MAX
unsigned int genRandom() {// 使用随机设备作为种子std::random_device rd;// 使用 Mersenne Twister 引擎std::mt19937 gen(rd());// 定义分布范围 [INT_MIN, INT_MAX]std::uniform_int_distribution<> distr(0, INT_MAX);// 生成并输出随机数unsigned int result = distr(gen);return result;
}int main(int argc, char** argv) {system("color 02");printf("argc=%d\n", argc);int ret = -1;// 生成随机数unsigned int num = genRandom();//int num = INT_MIN;printf("num = %d\n", num);// 先把随机32位整数转换成 unsigned char 数组,再转换回 32 位整数unsigned char arr[ARR_SIZE];ret = intToUcharArr(num, ARR_SIZE, 0, arr);if (0 != ret) {printf("intToUcharArr error. ret=%d\n", ret);return -1;}unsigned int n2 = 0;ret = ucharArrToInt(arr, ARR_SIZE, 0, &n2);if (0 != ret) {printf("ucharArrToInt error. ret=%d\n", ret);return -1;}printf("n2  = %d\n", n2);if (num == n2) {printf("true\n");}else {printf("false\n");}return 0;
}
http://www.xdnf.cn/news/10784.html

相关文章:

  • 升级centos 7.9内核到 5.4.x
  • 更强劲,更高效:智源研究院开源轻量级超长视频理解模型Video-XL-2
  • ONLYOFFICE 与 LocalAI:在 Ubuntu 上搭建 AI 文档编辑环境
  • 法律大语言模型(Legal LLM)技术架构
  • 实验设计与分析(第6版,Montgomery著,傅珏生译) 第9章三水平和混合水平析因设计与分式析因设计9.5节思考题9.1 R语言解题
  • Stone 3D新版本发布,添加玩家控制和生物模拟等组件,增强路径编辑功能,优化材质编辑
  • 第3篇:数据库路由模块设计与 SQL 路由策略解析
  • 【IOS】GCD学习
  • centos中的ulimit命令
  • SpringCloud 分布式锁Redisson锁的重入性 高并发 获取锁
  • 「EN 18031」访问控制机制(ACM - 1):智能路由器的安全守卫
  • SuperMap GIS基础产品FAQ集锦(20250603)
  • 人工智能在智能教育中的创新应用与未来趋势
  • 人工智能AI之机器学习基石系列 第 3 篇:选择你的“学习方法”——初探监督学习与无监督学习
  • windows安装多个版本composer
  • 基于TI DSP控制的光伏逆变器最大功率跟踪mppt
  • go语言基础|slice入门
  • VR 虚拟仿真工器具:开启医学新视界的智慧钥匙​
  • 25年宁德时代新能源科技SHL 测评语言理解数字推理Verify题库
  • 基于Android的一周穿搭APP的设计与实现 _springboot+vue
  • Oracle、PostgreSQL 与 MySQL 数据库对比分析与实践指南
  • C++学习-入门到精通【13】标准库的容器和迭代器
  • NVIDIA DOCA 3.0:引领AI基础设施革命的引擎简析
  • Qwen3高效微调
  • k8s的出现解决了java并发编程胡问题了
  • [蓝桥杯]地址转换
  • 【ISAQB大纲解读】Kafka消息总线被视为“自下而上设计”?
  • 基于PostGIS的GeoTools执行原生SQL查询制图实践-以贵州省行政区划及地级市驻地为例
  • Python Pytest
  • 接口自动化测试之pytest接口关联框架封装