Reputation: 2572
I tried to get the systems byte encoding (endian) at compile time to make a template specialization for converting integers (bigger than 32 bit) between host endian and network endian. Unfortunately i did not find a working solution which works with C++11 at compile time and without a external library (e.g. boost).
I decided to write a general code for (unsigned) integers with a size bigger than 32 bit and it seems to work on my local machine:
#include <climits>
#include <cstdint>
#include <iostream>
template<typename T>
T host_to_network(const T& value) {
char tmp[sizeof(T)];
size_t i, shift = 0;
for (size_t i = 0; i < sizeof(T); ++i) {
tmp[sizeof(T) - 1 - i] = (value >> shift) & 0xFF;
shift += CHAR_BIT;
}
return *reinterpret_cast<const T *>(tmp);
}
template<typename T>
T network_to_host(const T& value) {
char tmp[sizeof(T)];
*reinterpret_cast<T *>(tmp) = value;
size_t shift = 0;
T result;
for (size_t i = 0; i < sizeof(T); ++i) {
result |= tmp[sizeof(T) - 1 - i] << shift;
shift += CHAR_BIT;
}
return result;
}
int main() {
uint32_t xxx = 1234;
//int16_t xxx = -12;
std::cout << host_to_network(xxx) << std::endl;
std::cout << network_to_host(xxx) << std::endl;
std::cout << host_to_network(network_to_host(xxx)) << std::endl;
}
Unfortunately i'm not sure if this works for any architecture or at least for hosts with little and big endian. My computer uses little endian and it seems to work here. Does anyone see a bug in the code? Or could someone check it with big endian?
For signed integers the code does not work, but i don't know why. Could someone give me a hint?
I know this code is slow if the host endian is equal to the local endian, but this is no problem for my use case.
Thank you very much
Best regards
Kevin
Upvotes: 0
Views: 569
Reputation: 1183
Easy identification and conversion. This is such a frequent operation so frequently done by detection looping and shifting that I felt I should offer the method I have been using for over a decade for other people to use to advantage.
A common operation is to split a display RGBA array into R, G, B, and A planes. Use pre-calculated indices like these endian-invariant offsets:
A = (0x03020100>>0x18)&0xff;
B = (0x03020100>>0x10)&0xff;
G = (0x03020100>>0x08)&0xff;
R = (0x03020100>>0x00)&0xff;
The values are 0,1,2,3 for one endianness and 3,2,1,0 for the other. Many compilers perform the calculation and turn these into manifest constants. No more order-dependent bit-shifting to extract individual components. I leave it to the reader to rename these to suit the taste of their choice.
In C:
unsigned long source = 0x01234567, target = 0x0;
unsigned char src = (unsigned char *)&source;
unsigned char tgt = (unsigned char *)⌖
tgt[A] = src[R]; tgt[B] = src[G]; tgt[G] = src[B]; tgt[R] = src[A];
In Python, javascript, PHP and probably many others:
src = [0x01, 0x23, 0x45, 0x67]
tgt = [0,0,0,0]
tgt[A] = src[R]; tgt[B] = src[G]; tgt[G] = src[B]; tgt[R] = src[A];
Enjoy the (sometimes significant) performance boost, and clarity of use my friends.
If anyone is interested, I will offer a convolution/correlation performance boost technique.
Upvotes: 1