简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!
优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课【原创干货持续更新中……】🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
🍉🍉🍉文章目录🍉🍉🍉
- 🌻1.前言
- 🌻2.大小端介绍
- 🐓2.1 大端模式
- 🐓2.2 小端模式
- 🐓2.3 作用及应用
- 🐓2.4结论
- 🌻3.代码实例
- 🐓3.1 C++处理大端、小端数据
- 🐓3.2 Android处理大端、小端数据
- 🐓3.3 C语言处理大端、小端数据
🌻1.前言
本篇目的:C++与Android处理16进制大端/小端数据实例
🌻2.大小端介绍
- 大小端模式是指计算机系统中多字节数据的存储方式和传输方式,它主要分为大端模式(Big-Endian)和小端模式(Little-Endian)。
🐓2.1 大端模式
- 在大端模式中,高字节存储在低地址位置,而低字节存储在高地址位置。换句话说,一个数的最高有效字节(Most Significant Byte, MSB)存放在内存的起始位置。大端模式的特点是数据的书写顺序与其在内存中的存储顺序一致,这样在查看内存时,数据看起来更直观。例如,对于一个32位整数0x12345678,在大端模式下的存储顺序如下:
地址 值
0x00 12
0x01 34
0x02 56
0x03 78
🐓2.2 小端模式
小端模式则是将低字节存储在低地址位置,高字节存储在高地址位置。即最低有效字节(Least Significant Byte, LSB)放在内存的起始位置。与大端模式相反,小端模式的数据存储顺序和书写顺序相反。例如,对于同样的32位整数0x12345678,在小端模式下的存储顺序如下:
地址 值
0x00 78
0x01 56
0x02 34
0x03 12
🐓2.3 作用及应用
- 大小端模式的选择与计算机的体系结构和应用需求有关。不同的处理器体系结构可能会采用不同的字节存储方式。
-
网络通信:在网络通信中,大端模式(也称为网络字节序)被广泛采用。这是因为大端模式在数据传输时,最高有效字节先传输,便于数据在不同系统之间进行一致的传递和解释。互联网协议(如TCP/IP)就使用大端模式,这使得不同设备之间的数据交换更为统一和标准化。
-
跨平台数据处理:当程序需要在不同平台上运行时(例如在不同的处理器架构之间传递数据),了解并处理大小端模式是必要的。某些处理器(如x86架构)采用小端模式,而其他处理器(如某些RISC架构)可能采用大端模式。在这种情况下,程序需要正确地转换数据的字节顺序,以确保数据的一致性和正确性。
-
文件格式和数据存储:某些文件格式或数据存储协议可能规定了特定的字节序。例如,WAV音频文件和许多图像文件格式规定了使用小端模式存储数据。这种规定确保了文件在不同系统上读取时的一致性。
🐓2.4结论
- 大小端模式是计算机系统中处理多字节数据的重要概念,理解和正确应用这些模式对于开发跨平台软件、网络协议和处理特定文件格式至关重要。
- 大端模式以其直观的内存布局适用于网络通信和标准化的数据传输,而小端模式由于其在某些处理器上的效率优势,被广泛应用于多种处理器架构中。在实际应用中,根据具体需求选择合适的字节序模式是确保数据正确处理的关键。
🌻3.代码实例
🐓3.1 C++处理大端、小端数据
#include <iostream>
#include <iomanip>
#include <vector>
#include <cstdint>
// 判断系统是否为小端
bool isLittleEndian() {
uint16_t number = 0x1;
return (*(char *)&number == 0x1);
}
// 进行字节序转换(32位)
uint32_t swapEndian32(uint32_t val) {
return ((val >> 24) & 0x000000FF) |
((val >> 8) & 0x0000FF00) |
((val << 8) & 0x00FF0000) |
((val << 24) & 0xFF000000);
}
// 打印缓冲区内容(小端字节序)
void printBufferLittleEndian(const std::vector<uint8_t>& buffer, const std::string& bufferName) {
std::string bufferHex;
for (size_t i = 0; i < buffer.size(); i += 4) {
uint32_t val = 0;
// 读取4个字节
for (size_t j = 0; j < 4 && (i + j) < buffer.size(); ++j) {
val |= (static_cast<uint32_t>(buffer[i + j]) << (j * 8));
}
// 如果系统不是小端字节序,则需要转换字节序
if (!isLittleEndian()) {
val = swapEndian32(val);
}
// 将4字节的值转换为十六进制字符串
std::ostringstream hexStream;
hexStream << std::setfill('0') << std::setw(8) << std::hex << val;
bufferHex += hexStream.str() + " ";
}
std::cout << bufferName << ": " << bufferHex << std::endl;
}
// 打印write_buffer的内容
void printWriteBuffer(const std::vector<uint8_t>& writeBuffer) {
printBufferLittleEndian(writeBuffer, "Write Buffer");
}
// 打印read_buffer的内容
void printReadBuffer(const std::vector<uint8_t>& readBuffer) {
printBufferLittleEndian(readBuffer, "Read Buffer");
}
int main() {
// 初始化示例数据
std::vector<uint8_t> writeBuffer(256);
for (int i = 0; i < 256; ++i) {
writeBuffer[i] = static_cast<uint8_t>(i);
}
std::vector<uint8_t> readBuffer(256);
for (int i = 0; i < 256; ++i) {
readBuffer[i] = static_cast<uint8_t>(255 - i);
}
// 打印缓冲区内容
printWriteBuffer(writeBuffer);
printf("\n");
printReadBuffer(readBuffer);
return 0;
}
🐓3.2 Android处理大端、小端数据
#include <cutils/log.h>
#include <iomanip>
#include <stdint.h>
// 判断系统是否为小端
bool isLittleEndian() {
uint16_t number = 0x1;
return (*(char *)&number == 0x1);
}
// 进行字节序转换(32位)
uint32_t swapEndian32(uint32_t val) {
return ((val >> 24) & 0x000000FF) |
((val >> 8) & 0x0000FF00) |
((val << 8) & 0x00FF0000) |
((val << 24) & 0xFF000000);
}
// 打印缓冲区内容(小端字节序)
void printBufferLittleEndian(const char* buffer, size_t size, const char* bufferName) {
std::string bufferHex;
for (size_t i = 0; i < size; i += 4) {
uint32_t val = 0;
// 读取4个字节
for (size_t j = 0; j < 4 && (i + j) < size; ++j) {
val |= (static_cast<uint32_t>(static_cast<uint8_t>(buffer[i + j])) << (j * 8));
}
// 如果系统不是小端字节序,则需要转换字节序
if (!isLittleEndian()) {
val = swapEndian32(val);
}
// 将4字节的值转换为十六进制字符串
char hex[9];
snprintf(hex, sizeof(hex), "%08x", val);
bufferHex += hex;
bufferHex += " ";
}
ALOGE("%s: %s", bufferName, bufferHex.c_str());
}
// 打印write_buffer的内容
void printWriteBuffer(const binder_write_read& bwr) {
const char* writeBuffer = reinterpret_cast<const char*>(bwr.write_buffer);
printBufferLittleEndian(writeBuffer, bwr.write_size, "Write Buffer");
}
// 打印read_buffer的内容
void printReadBuffer(const binder_write_read& bwr) {
const char* readBuffer = reinterpret_cast<const char*>(bwr.read_buffer);
printBufferLittleEndian(readBuffer, bwr.read_size, "Read Buffer");
}
int main() {
binder_write_read bwr;
// 初始化示例数据
bwr.write_size = 256;
char writeData[256];
for (int i = 0; i < 256; ++i) {
writeData[i] = i;
}
bwr.write_buffer = reinterpret_cast<binder_uintptr_t>(writeData);
bwr.read_size = 256;
char readData[256];
for (int i = 0; i < 256; ++i) {
readData[i] = 255 - i;
}
bwr.read_buffer = reinterpret_cast<binder_uintptr_t>(readData);
// 打印缓冲区内容
printWriteBuffer(bwr);
printReadBuffer(bwr);
return 0;
}
🐓3.3 C语言处理大端、小端数据
/***********************************************************
* Author : 公众号: Android系统攻城狮
* Create time : 2024-05-21 10:07:14 星期二
* Filename : little_big_duan_for_C.cpp
* Description :
************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
// 判断系统是否为小端
bool isLittleEndian() {
uint16_t number = 0x1;
return (*(char *)&number == 0x1);
}
// 进行字节序转换(32位)
uint32_t swapEndian32(uint32_t val) {
return ((val >> 24) & 0x000000FF) |
((val >> 8) & 0x0000FF00) |
((val << 8) & 0x00FF0000) |
((val << 24) & 0xFF000000);
}
// 打印缓冲区内容(小端字节序)
void printBufferLittleEndian(const char* buffer, size_t size, const char* bufferName) {
char bufferHex[1024] = {0}; // 假设缓冲区最大为1024字节
char hex[9];
for (size_t i = 0; i < size; i += 4) {
uint32_t val = 0;
// 读取4个字节
for (size_t j = 0; j < 4 && (i + j) < size; ++j) {
val |= (uint32_t)((uint8_t)buffer[i + j]) << (j * 8);
}
// 如果系统不是小端字节序,则需要转换字节序
if (!isLittleEndian()) {
val = swapEndian32(val);
}
// 将4字节的值转换为十六进制字符串
snprintf(hex, sizeof(hex), "%08x", val);
strncat(bufferHex, hex, sizeof(bufferHex) - strlen(bufferHex) - 1);
strncat(bufferHex, " ", sizeof(bufferHex) - strlen(bufferHex) - 1);
}
printf("%s: %s\n", bufferName, bufferHex);
}
// 假设binder_write_read_01结构如下
typedef struct {
void* write_buffer;
size_t write_size;
void* read_buffer;
size_t read_size;
} binder_write_read_01;
// 打印write_buffer的内容
void printWriteBuffer(const binder_write_read_01* bwr) {
const char* writeBuffer = (const char*)(bwr->write_buffer);
printBufferLittleEndian(writeBuffer, bwr->write_size, "Write Buffer");
}
// 打印read_buffer的内容
void printReadBuffer(const binder_write_read_01* bwr) {
const char* readBuffer = (const char*)(bwr->read_buffer);
printBufferLittleEndian(readBuffer, bwr->read_size, "Read Buffer");
}
int main() {
// 示例使用
uint8_t write_data[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
uint8_t read_data[] = {0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
binder_write_read_01 bwr = {write_data, sizeof(write_data), read_data, sizeof(read_data)};
printWriteBuffer(&bwr);
//printReadBuffer(&bwr);
return 0;
}