简体   繁体   中英

How to std::reverse_copy bytes of an int into char array

I'm learning socket programming and need to convert data from host byte order(in my case LITTLE ENDIAN) to network byte order. So I need to swap the byte order of the data that I will be sending. So, I used to std::memcpy say integer into a temp char array, then swap the bytes of that temp char array. But now I'm trying to achieve the same using std::reverse_copy but not been able to achieve(not compiling itself). This is my sample code:

#include <iostream>
#include <cstring>
#include <algorithm>

int main()
{
    const int a = 0x89ABCDEF;
    char arr[sizeof(decltype(a))] {};
    char r_arr[sizeof(decltype(a))] {};
    
    std::memcpy(arr, reinterpret_cast<const char*>(&a), sizeof(decltype(a)));
    char *start = arr;
    char *end = arr + sizeof(decltype(a)) - 1;
    while (start < end) {
        char temp = *start;
        *start = *end;
        *end = temp;
        
        ++start;
        --end;
    }
    for (int32_t i = 0; i < sizeof(decltype(a)); ++i)
        std::cout << std::hex << static_cast<uint16_t>(arr[i]) << std::endl;
    
    // error in below line
    // std::reverse_copy(std::begin(reinterpret_cast<const char*>(&a)), std::begin(reinterpret_cast<const char*>(&a)) + sizeof(decltype(a)), std::begin(r_arr));
    for (int32_t i = 0; i < sizeof(decltype(a)); ++i)
        std::cout << std::hex << static_cast<uint16_t>(r_arr[i]) << std::endl;
        
    return 0;
}

You have too many calls to std::begin . You want just:

std::reverse_copy(reinterpret_cast<const char*>(&a), reinterpret_cast<const char*>(&a) + sizeof(decltype(a)), r_arr);

This calls for a type-casting view that can be used both in C++20 ranges-based code and in iterators-based pre-C++20 code. That way you don't need to mess with temporary char buffers etc.

#include <algorithm>

template <typename Src>
class const_char_view_t {
    const Src &src;
public:
    explicit const_char_view_t(const Src &src) : src(src) {}
    const char * begin() const noexcept {
        return reinterpret_cast<const char*>(&src);
    }
    const char * end() const noexcept { 
        return reinterpret_cast<const char*>((&src)+1);
    }
};

template <typename Src>
auto const_char_view(const Src &val) {
    return const_char_view_t<Src>(val);
}

template <typename Out>
class tie_out_adapter_t {
    Out &out;
public:
    explicit tie_out_adapter_t(Out &out) : out(out) {}
    template <typename Src>
    Out &operator=(Src &&src) {
        return (out = std::move(src.out));
    }
};
template <typename Out>
auto tie_out(Out && out) { return tie_out_adapter_t(out); }

The usage example below demonstrates the use of the above, as well as how to use the iterators returned by std::[ranges::]reverse_copy to concatenate successive elements into an output vector.

To use ranges, -std=c++20 (at least) compiler option has to be provided to gcc, clang and MSVC.

#include <cassert>
#include <iterator>
#include <vector>
#ifdef __has_include
#   if __has_include(<version>)
#   include <version>
#       if __cpp_lib_ranges >= 201911L
#       define HAS_RANGES 1
#       endif
#   endif
#endif

int main() {
    int32_t val_1 = 0x01234567;
    int16_t val_2 = 0x89AB;
    const char copy_expected[4+2] = {'\x01','\x23','\x45','\x67','\x89','\xAB'};

    #if HAS_RANGES
    {
        std::vector<char> copy;
        auto out = std::back_inserter(copy);
        tie_out(out) = std::ranges::reverse_copy(const_char_view(val_1), out);
        tie_out(out) = std::ranges::reverse_copy(const_char_view(val_2), out);
        assert(std::ranges::equal(copy, copy_expected));
        copy.clear();
    }
    #endif

    std::vector<char> copy;
    auto out = std::back_inserter(copy);
    out = std::reverse_copy(cchar_begin(val_1), cchar_end(val_1), out);
    out = std::reverse_copy(cchar_begin(val_2), cchar_end(val_2), out);
    assert(std::equal(std::begin(copy), std::end(copy), std::begin(copy_expected)));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM