首页 > 其他分享 >小端对齐+大端对齐进阶版本V3.0

小端对齐+大端对齐进阶版本V3.0

时间:2024-04-13 22:13:45浏览次数:13  
标签:小端 std 存储 字节 大端 对齐 size

当涉及到多字节的数据类型(如 uint16_tuint32_t 等)时,字节在内存中的存储顺序会影响到数据的解释方式。这个存储顺序可以分为两种:大端对齐(Big Endian)和小端对齐(Little Endian)。

大端对齐(Big Endian):

在大端对齐中,数据的高字节(Most Significant Byte,MSB)存储在内存的低地址,而数据的低字节(Least Significant Byte,LSB)存储在内存的高地址。举个例子,考虑一个 16 位无符号整数 0x1234

  • 内存中的存储顺序是:0x12(高地址)0x34(低地址)。

  • 在二进制流中,高位字节排在前面,低位字节排在后面( 12 34)。

小端对齐(Little Endian):

在小端对齐中,数据的低字节(LSB)存储在内存的低地址,而数据的高字节(MSB)存储在内存的高地址。以同样的例子 0x1234 为例:

  • 内存中的存储顺序是:0x34(低地址)0x12(高地址)。

  • 在二进制流中,低位字节排在前面,高位字节排在后面( 34 12)。

 

在现代计算机中,数据通常是按照小端存储的。这意味着在多字节数据类型(如整数、浮点数等)的存储中,最低有效字节(Least Significant Byte,LSB)存储在最低地址,而最高有效字节(Most Significant Byte,MSB)存储在最高地址。

对于 std::memcpy 函数,它只是简单地从源地址开始,按照字节顺序连续地复制数据到目标地址。它不会考虑数据的大小端存储方式。因此,无论源数据是小端存储还是大端存储,std::memcpy 都会按照字节的顺序进行拷贝。这就意味着,当你使用 std::memcpy 从一个变量复制到另一个变量时,字节的存储顺序会被保留。

 

进一步解释,如果计算机里定义了变量  uint16_t  testa=0x1234。它在计算机里面是小端对齐(一般的计算机都是小端对齐)存放的,存放格式是 34 12。

因此,在将小端对齐的二进制流,使用memcpy拷贝的时候,比如拷贝2个字节,赋值给 uint16_t testb 的时候,它是不需要进行 高低位转换的。计算机里面存的顺序,就是 小端对齐 存的顺序。

 


大端对齐,就不同了。如果计算机里定义了变量  uint16_t  testa=0x1234。它在计算机里面是小端对齐(一般的计算机都是小端对齐)存放的,存放格式是 34 12

此时我们有一个  大端对齐的二进制流,它里面如果存放了testa,它在这个二进制流里面存放格式是  12 34 ,但是它在计算出中存放格式应该是 34 12(小端对齐格式)。

因此,大端对齐的时候,要从后往前取数据(先把低地址位置的数据取了, 34 是低地址位的数据)

 

 


最后,字符串没有大小端对齐的概念。闭眼 memcpy即可。

 

 

#include <iostream>  
#include <vector>
#include <cstring>
#include <iomanip>
#include <cstdint>


void appendLittleEndian(std::vector<uint8_t>& block, const void* data, size_t size) {
    const uint8_t* bytes = static_cast<const uint8_t*>(data);
    for (size_t i = 0; i < size; ++i) {
        block.push_back(bytes[i]);
    }
}


void appendBigEndian(std::vector<uint8_t>& block, const void* data, size_t size) {
    const uint8_t* bytes = static_cast<const uint8_t*>(data);
    for (size_t i = size; i > 0; --i) {
        block.push_back(bytes[i - 1]);
    }
}


template<typename T>
void parseLittleEndian(const std::vector<uint8_t>& block, size_t& offset, T& value) {
    std::memcpy(&value, block.data() + offset, sizeof(T));
    offset += sizeof(T);
}


template<typename T>
void parseBigEndian(const std::vector<uint8_t>& block, size_t& offset, T& value) {
    value = 0;
    for (size_t i = 0; i < sizeof(T); ++i) {
        value <<= 8;
        value |= block[offset + i];
    }
    offset += sizeof(T);
}



int main() {
    std::vector<uint8_t> littleEndianBlock;
    std::vector<uint8_t> bigEndianBlock;
    uint16_t num16 = 0x1234;  // 4660
    uint32_t num32 = 0x56000078; //1442840696
    
    // Append uint16_t (2 bytes) in little-endian format
    appendLittleEndian(littleEndianBlock, &num16, sizeof(num16));
    // Append uint32_t (4 bytes) in little-endian format
    appendLittleEndian(littleEndianBlock, &num32, sizeof(num32));


    appendBigEndian(bigEndianBlock, &num16, sizeof(num16));
    appendBigEndian(bigEndianBlock, &num32, sizeof(num32));
    
    // Output binary stream
    std::cout << "Binary Stream in little-endian format:\n";
    for (uint8_t byte : littleEndianBlock) {
        std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(byte) << " ";
    }
    std::cout << std::endl;

    std::cout << "Binary Stream in big-endian format:\n";
    for (uint8_t byte : bigEndianBlock) {
        std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(byte) << " ";
    }
    std::cout << std::endl;

    //============================================
    size_t offset = 0;
    uint16_t little_a=0;
    uint32_t little_b=0;
    parseLittleEndian(littleEndianBlock,offset, little_a);
    parseLittleEndian(littleEndianBlock,offset, little_b);
    std::cout<<std::dec;
    std::cout<<"offset:"<<offset<<",block.size:"<<littleEndianBlock.size()<<",little_a:"<<static_cast<int>(little_a)<<",little_b:"<<static_cast<int>(little_b)<<std::endl;


    //parseBigEndian
    size_t offset2 = 0;
    uint16_t big_a=0;
    uint32_t big_b=0;
    parseBigEndian(bigEndianBlock, offset2, big_a);
    parseBigEndian(bigEndianBlock, offset2, big_b);
    std::cout<<std::dec;
    std::cout<<"offset2:"<<offset2<<",block.size:"<<bigEndianBlock.size()<<",big_a:"<<static_cast<int>(big_a)<<",big_b:"<<static_cast<int>(big_b)<<std::endl;

    return 0;
}

/************************************************
uint16_t num16 = 0x1234;  // 4660
uint32_t num32 = 0x56000078; //1442840696

Binary Stream in little-endian format:
34 12 78 00 00 56 

Binary Stream in big-endian format:
12 34 56 00 00 78 

offset:6,block.size:6,little_a:4660,little_b:1442840696
offset2:6,block.size:6,big_a:4660,big_b:1442840696
**************************************************/

 

标签:小端,std,存储,字节,大端,对齐,size
From: https://www.cnblogs.com/music-liang/p/18133462

相关文章

  • 解密prompt系列27. LLM对齐经验之如何降低通用能力损失
    前面我们已经聊过众多指令微调的方案,这一章我们重点讨论下如何注入某一类任务或能力的同时,尽可能不损失模型原有的通用指令理解能力。因为在下游或垂直领域应用中,我们设计的推理任务风格或形式,往往很难通过prompt来稳定实现。这种情况下就会依赖微调来注入稳定的推理风格,但同时在......
  • 大端与小端
    小端:低字节存在低内存地址大端:低字节存在高内存地址举例:十进制数8,假设整型占4个字节8的二进制:00000000000000000000000000004000高字节       ---------->        低字节内存地址:低内存地址       ---------->    高......
  • 结构体中的内存对齐
    结构体中的内存对齐内存对齐规则在C语言中,结构体的内存布局并不是简单地将成员依次排列在内存中,而是遵循一定的内存对齐规则。这些规则确保了数据结构在内存中存储的方式既高效又符合硬件平台的限制。问题提出structS1{charc1;inti;charc2;};structS2{int......
  • 将一个结构体里面的数据转为 小端对齐的二进制流
    现在有一个C++的结构体,需要把它转为二进制流,而且是小端对齐的。我们还需要将一个小端对齐的二进制流,转为对应的结构体。appendLittleEndianparseLittleEndian这2个方法是chatgpt提供给我的,功能能准确实现。代码也比较简洁。 #include<iostream>#include<vector>#inc......
  • js context.fillText 征对不同长度右边对齐的解决办法
    在HTML5Canvas中,要实现文本右对齐并且与不同长度文本互不重叠,可以通过测量文本宽度,并基于文本宽度设置x坐标来实现。以下是一个简单的JavaScript函数,用于在Canvas中右对齐并且不重叠地绘制文本:functiondrawRightAlignedText(context,text,x,y){//测量文本宽度......
  • 芒果YOLOv5改进90:标签分配策略篇之TOOD:最新基于Task-aligned Assignment任务对齐学习T
    芒果专栏基于TOOD的改进,改进Task-alignedAssignment任务对齐学习源码教程|详情如下......
  • 芒果YOLOv7改进90:标签分配策略篇之TAL:最新基于Task-aligned Assignment任务对齐学习TA
    芒果专栏基于TOOD的改进,改进Task-alignedAssignment任务对齐学习源码教程|详情如下......
  • 整型之韵,数之舞:大小端与浮点数的内存之旅
    ✨✨欢迎......
  • 大端序,小端序,Big-endian, Little-endian
    在计算机中,字节序(byteorder)指的是多字节数据在存储时字节的排列顺序。主要有两种字节序:大端序(big-endian)和小端序(little-endian)。大端序(Big-endian):在大端序中,最高有效字节(MostSignificantByte,MSB)存储在最低的内存地址,而最低有效字节(LeastSignificantByte,LSB)存储在最高的内......
  • Qt 大小端字节序转换的方法
    在Qt中,可以使用qToLittleEndian和qToBigEndian两个函数来实现大小端字节序之间的转换。1.转换为小端字节序:1quint32num=0x12345678;2quint32littleEndianNum=qToLittleEndian(num);//转换为小端字节序2.转换为大端字节序:1quint32num=0x12345678;2quint......