C++ 跨具有不同端性的不同平台使用memcpy

C++ 跨具有不同端性的不同平台使用memcpy,c++,endianness,memcpy,C++,Endianness,Memcpy,我正在编写一个函数,它将uint32_t中的数据复制到std::vector中。该程序将用于不同终端的不同平台(主要是LE,但有些是be) 目前我使用的是: std:vector<uint8_t> Decryption::GenerateIvForBlock(uint32_t blockNumber) { std:vector<uint8_t> ivInput(AES128_KEY_BYTE_LENGTH, 0); // Some code if (//////

我正在编写一个函数,它将uint32_t中的数据复制到std::vector中。该程序将用于不同终端的不同平台(主要是LE,但有些是be)

目前我使用的是:

std:vector<uint8_t> Decryption::GenerateIvForBlock(uint32_t blockNumber)
{
    std:vector<uint8_t> ivInput(AES128_KEY_BYTE_LENGTH, 0);

// Some code
if (///////)
{
    memcpy(&ivInput[0], &blockNumber, sizeof(blockNumber));
}
} 
std:vector Decryption::GenerateIvForBlock(uint32_t blockNumber)
{
标准:向量ivInput(AES128密钥字节长度,0);
//一些代码
如果(//)
{
memcpy(&ivInput[0],&blockNumber,sizeof(blockNumber));
}
} 
目前,不同endian类型的平台之间的行为不同,即使平台之间的blockNumber相同。
不幸的是,我不能很容易地测试Big-endian系统,所以我努力地找出一个解决方案。

作为πάνταῥεῖ 建议使用
ntohx()
/
htonx()
函数可以帮助您将16位和32位无符号整数从网络字节顺序转换为主机字节顺序,然后再转换回主机字节顺序

<> P>有一些草稿包括了在C++(代码> >代码>标题中的<代码> NtoHe()/<代码>和<代码> HtON()/<代码>,但没有成功。您可能会在
中找到C函数,因此您可以自己创建模板。例如:

#include <cstdint>
#ifdef _WIN32
 #include <Winsock2.h>
#else
 #include <arpa/inet.h>
#endif

template <class T>
T hton(T host) noexcept = delete;

template <>
uint8_t hton(uint8_t host) noexcept {
    return host;
}

template <>
uint16_t hton(uint16_t host) noexcept {
    return htons(host);
}

template <>
uint32_t hton(uint32_t host) noexcept {
    return htonl(host);
}

template <class T>
T ntoh(T network) noexcept = delete;

template <>
uint8_t ntoh(uint8_t network) noexcept {
    return network;
}

template <>
uint16_t ntoh(uint16_t network) noexcept {
    return ntohs(network);
}

template <>
uint32_t ntoh(uint32_t network) noexcept {
    return ntohl(network);
}
#包括
#ifdef_WIN32
#包括
#否则
#包括
#恩迪夫
模板
T hton(T主机)noexcept=delete;
模板
uint8\u t hton(uint8\u t主机)不例外{
返回主机;
}
模板
uint16\u t主机(uint16\u t主机)无例外{
返回HTON(主机);
}
模板
uint32_t hton(uint32_t主机)不例外{
返回htonl(主机);
}
模板
T ntoh(T网络)noexcept=delete;
模板
uint8_t ntoh(uint8_t网络)不例外{
返回网络;
}
模板
uint16\t ntoh(uint16\t网络)不例外{
返回NTOH(网络);
}
模板
uint32_t ntoh(uint32_t网络)不例外{
返回ntohl(网络);
}
有了这些,您可以使用流操作符为向量创建包装类模板,以保存和恢复数据。下面是一个非常基本的例子。根据需要添加操作员等

template <typename T>
class Data {
    std::vector<T> m_data;
public:
    Data() : m_data{} {}

    template< class... Args >
    auto emplace_back( Args&&... args ) {
        return m_data.emplace_back(std::forward<Args>(args)...);
    }
    void reserve(typename std::vector<T>::size_type size) {
        m_data.reserve(size);
    }
    bool operator==(const Data& o) {
        return m_data == o.m_data;
    }

    template <typename V>
    friend std::ostream& operator<<(std::ostream&, const Data<V>&);
    template <typename V>
    friend std::istream& operator>>(std::istream&, Data<V>&);
};

template <typename T>
std::ostream& operator<<(std::ostream& os, const Data<T>& d) {
    // write the number of entries first
    const uint32_t count = hton(static_cast<const uint32_t>(d.m_data.size()));
    os.write(reinterpret_cast<const char*>(&count), sizeof(count));
    // write all the entries, converted to network byte order
    for(auto v : d.m_data) {
        v = hton(v);
        os.write(reinterpret_cast<const char*>(&v), sizeof(v));
    }
    return os;
}

template <typename T>
std::istream& operator>>(std::istream& is, Data<T>& d) {
    // read the number of entries first
    uint32_t count;
    is.read(reinterpret_cast<char*>(&count), sizeof(count));
    d.m_data.resize(ntoh(count));
    // read all the entries and convert to host byte order
    for(auto& v : d.m_data) {
        is.read(reinterpret_cast<char*>(&v), sizeof(v));
        v = ntoh(v);
    }
    return is;
}
模板
类数据{
std::向量m_数据;
公众:
Data():m_Data{}{}
模板<类…参数>
自动放置回(Args&&…Args){
返回m_数据。将m_放置回(标准::前进(args)…);
}
无效保留(typename std::vector::size\u type size){
m_数据保留(大小);
}
布尔运算符==(常量数据和o){
返回m_数据==o.m_数据;
}
模板
friend std::ostream&operator(std::istream&,Data&);
};
模板
std::ostream&operator(std::istream&is、数据与数据){
//首先读取条目数
uint32_t计数;
is.read(重新解释强制转换(&count),sizeof(count));
d、 m_data.resize(ntoh(count));
//读取所有条目并转换为主机字节顺序
用于(自动和验证:d.m_数据){
is.read(重新解释铸造(&v),尺寸(v));
v=ntoh(v);
}
回报是;
}
测试:

#包括
#包括
#包括
int main(){
数据源;
数据副本;
std::stringstream-ss;
原始储备(1024*1024);
for(未签名的i=0;i复制;//从流还原

如果(orig==copy)std::cout,那么您应该停止使用
memcpy
?您想用它实现什么?对于这种情况,
ntohx()
/
htonx()
函数族可能会派上用场。不要使用
memcpy()
。数据正在系统之间移动。要至少测试little-endian端,请编写一个程序,通过以Big-endian格式向little-endian系统提供数据来模拟Big-endian系统。这只是问题的一半,但正确使用little-endian端会给您一些提示,让您对Big-endian系统有足够的信心在gnu上有bswap_16(x);bswap_32(x);bswap_64(x);在byteswap中。h@OznOg无条件字节切换不会有帮助。首先需要确定是否需要它,可能需要使用C++20测试
if(std::endian::native!=std::endian::big)
但也有棘手的
混合
endian需要处理。
#include <iostream>
#include <vector>
#include <sstream>

int main() {
    Data<unsigned> orig;
    Data<unsigned> copy;
    std::stringstream ss;
    orig.reserve(1024*1024);
    for(unsigned i=0; i<1024*1024; ++i) orig.emplace_back(i);
    ss << orig; // save to stream
    // the data in 'ss' is now in network byte order
    ss >> copy; // restore from stream
    if(orig==copy) std::cout << "happy\n";
}