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.