4
\$\begingroup\$

I'm working on a little endian machine and in my program I need to convert 2,3,4,5 or 8 bytes into network order before transmitting them over the network. I've written the following function which basically just reverses the bytes. I just wanted to make sure if it's logic is correct.

 void convertLittleToBig(const uint8_t* in, uint8_t* out, const uint64_t& sizeInBytes) {
 for(int i=0;i<sizeInBytes;++i)
 out[i] = in[sizeInBytes-i-1];
 }

The function assumes that 'out' and 'in' will be pointing at 'sizeInBytes' memory. If I'm not wrong, I can use the same function to convert from network order into little endian. Basically big endian and little endian, are mirror images of each other in terms of their byte order as per my current understanding.

Given below is a sample program:

#include <iostream>
#include <cstdint>
#include <iostream>
using std::cin;
//This function prints the raw bytes in memory.
void printBytes(const uint8_t* p, const uint64_t size) {
for(int i=0;i<size;++i)
 printf("\nbyte[%d](%x)",i+1,p[i]);
printf("\n");
}
void convertLittleToBig(const uint8_t* in, uint8_t* out, const uint64_t& sizeInBytes) {
 printf("\nCurrent representation\n");
 printBytes(in,sizeInBytes);
 for(int i=0;i<sizeInBytes;++i)
 out[i] = in[sizeInBytes-i-1];
 printf("\nRepresentation after conversion\n");
 printBytes(out,sizeInBytes);
}
int main() {
 uint64_t little;
 printf("\nEnter a number that you wish to convert into big endian: ");
 int64_t inp;
 cin>>inp;
 little=inp;
 uint64_t big;
 convertLittleToBig((uint8_t*)&little,(uint8_t*)&big,sizeof(big));
}
asked Feb 19, 2020 at 10:05
\$\endgroup\$
2
  • \$\begingroup\$ There are standard libs for this: htonl => host to network long linux.die.net/man/3/htonl \$\endgroup\$ Commented Feb 19, 2020 at 20:23
  • \$\begingroup\$ @MartinYork I have to convert 2,3,4,5 or 8 bytes. \$\endgroup\$ Commented Feb 20, 2020 at 8:44

1 Answer 1

7
\$\begingroup\$

Includes

We have included <iostream> twice, but missed <cstdio>.

Misspelt standard library identifiers

std::printf, std::uint8_t and std::uint64_t are consistently misspelt. You might sometimes get away with this, as your standard library is allowed to add global-namespace versions of those identifiers; since it's not required to do so, you have a portability bug.

Use appropriate size type

std::size_t is the appropriate type to use for the size of an object, rather than std::uint64_t (which could be unnecessarily big, or - theoretically, at least for now - too small).

Conversion function shouldn't have side-effects

The printf() calls within convertLittleToBig make it unusable in any serious program.

Consider a standard algorithm

The <algorithm> header provides a very useful std::copy() function we can use if we have a reverse iterator to copy from or to. We can get suitable iterators from std::span views onto the inputs (from C++20 onwards).

Avoid raw pointers

We could do better, using a template to accept values and return by value, inferring the size from the argument type:

#include <algorithm>
#include <span>
template<typename T>
T convertLittleToBig(const T& val)
{
 auto in = std::as_bytes(std::span(&val, 1));
 T result;
 auto out = std::as_writable_bytes(std::span(&result, 1));
 std::copy(in.rbegin(), in.rend(), out.begin());
 return result;
}

That's much simpler - no counting needed, and the caller doesn't need to use sizeof (to work with odd-sized values, they need to be passed as arrays).

This is how we'd use it in a simple test program:

#include <cstddef>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
 
std::string to_hex(auto const& val)
{
 std::ostringstream oss;
 oss << std::hex << std::setfill('0');
 auto in = std::as_bytes(std::span(&val, 1));
 for (auto c: in) {
 oss << std::setw(2) << std::to_integer<unsigned int>(c);
 }
 return oss.str();
}
// hex-print the value and its reversal
void demo_endian_swap(auto const& val)
{
 std::cout << to_hex(val) << " -> "
 << to_hex(convertLittleToBig(val)) << '\n';
}
#include <array>
int main() {
 // Demonstrate a selection of types
 demo_endian_swap(std::uint16_t{0x1234});
 demo_endian_swap(std::uint64_t{0x123456789abcde});
 demo_endian_swap(std::array<unsigned char,5>{1,2,3,4,5});
 //demo_endian_swap("abc"); // Invalid - can't return an array
 //demo_endian_swap(std::string{"abc"}); // oops - reverses whole structure
}

Example output:

3412 -> 1234
debc9a7856341200 -> 00123456789abcde
0102030405 -> 0504030201
answered Feb 19, 2020 at 13:48
\$\endgroup\$
4
  • \$\begingroup\$ C++20 is a tall requirement, particularly for environments often operating at the byte level — e.g., microcontrollers, though OP doesn't mention anything about standards; and your answer/solution immediately made me regret how much time I spent "optimizing" my own. \$\endgroup\$ Commented May 15, 2024 at 3:18
  • \$\begingroup\$ @ardnew, what do you mean by a "tall requirement"? std::span is ideal for microcontroller operations. It's certainly worth being careful about code size and dynamic allocation, but there's a good subset of C++20 that's perfect for these applications. \$\endgroup\$ Commented May 21, 2024 at 8:53
  • \$\begingroup\$ Agreed, with all of those points. My point is that many microcontroller vendor-default toolchains still do not include support for C++20, or even C++17 (Arduino AVR, STM32[GFL], etc.), regardless if the language is well-suited for the target or not. \$\endgroup\$ Commented May 22, 2024 at 17:35
  • \$\begingroup\$ Ah yes, if you're stuck with proprietary toolchains life will be more difficult. That's unfortunate. \$\endgroup\$ Commented May 22, 2024 at 17:41

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.