Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

64 bit ntohl() in C++?

The man pages for htonl() seem to suggest that you can only use it for up to 32 bit values. (In reality, ntohl() is defined for unsigned long, which on my platform is 32 bits. I suppose if the unsigned long were 8 bytes, it would work for 64 bit ints).

My problem is that I need to convert 64 bit integers (in my case, this is an unsigned long long) from big endian to little endian. Right now, I need to do that specific conversion. But it would be even nicer if the function (like ntohl()) would NOT convert my 64 bit value if the target platform WAS big endian. (I'd rather avoid adding my own preprocessor magic to do this).

What can I use? I would like something that is standard if it exists, but I am open to implementation suggestions. I have seen this type of conversion done in the past using unions. I suppose I could have a union with an unsigned long long and a char[8]. Then swap the bytes around accordingly. (Obviously would break on platforms that were big endian).

like image 324
Tom Avatar asked May 01 '09 01:05

Tom


People also ask

What is Ntohl in C?

The ntohl() function translates a long integer from network byte order to host byte order. Parameter Description a. The unsigned long integer to be put into host byte order. in_addr_t netlong. Is typed to the unsigned long integer to be put into host byte order.

Why do we use Htonl in C?

The htonl function takes a 32-bit number in host byte order and returns a 32-bit number in the network byte order used in TCP/IP networks (the AF_INET or AF_INET6 address family). The htonl function can be used to convert an IPv4 address in host byte order to the IPv4 address in network byte order.

What is the purpose of the functions Htonl and Ntohs?

The function htons converts an integer short number from the byte order accepted on the computer into the network byte order. The function ntohl converts an integer number from the network byte order into the byte order accepted on the computer.

Is Htonl the same as Ntohl?

So, both ntohl() and htonl() are merely byte swaps defined in byteswap. h. That is why your output is the same for both these macros.


2 Answers

Documentation: man htobe64 on Linux (glibc >= 2.9) or FreeBSD.

Unfortunately OpenBSD, FreeBSD and glibc (Linux) did not quite work together smoothly to create one (non-kernel-API) libc standard for this, during an attempt in 2009.

Currently, this short bit of preprocessor code:

#if defined(__linux__) #  include <endian.h> #elif defined(__FreeBSD__) || defined(__NetBSD__) #  include <sys/endian.h> #elif defined(__OpenBSD__) #  include <sys/types.h> #  define be16toh(x) betoh16(x) #  define be32toh(x) betoh32(x) #  define be64toh(x) betoh64(x) #endif 

(tested on Linux and OpenBSD) should hide the differences. It gives you the Linux/FreeBSD-style macros on those 4 platforms.

Use example:

  #include <stdint.h>    // For 'uint64_t'    uint64_t  host_int = 123;   uint64_t  big_endian;    big_endian = htobe64( host_int );   host_int = be64toh( big_endian ); 

It's the most "standard C library"-ish approach available at the moment.

like image 135
Nanno Langstraat Avatar answered Sep 29 '22 11:09

Nanno Langstraat


I would recommend reading this: http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html

#include <stdio.h> #include <stdint.h> #include <inttypes.h>  uint64_t ntoh64(const uint64_t *input) {     uint64_t rval;     uint8_t *data = (uint8_t *)&rval;      data[0] = *input >> 56;     data[1] = *input >> 48;     data[2] = *input >> 40;     data[3] = *input >> 32;     data[4] = *input >> 24;     data[5] = *input >> 16;     data[6] = *input >> 8;     data[7] = *input >> 0;      return rval; }  uint64_t hton64(const uint64_t *input) {     return (ntoh64(input)); }  int main(void) {     uint64_t ull;      ull = 1;     printf("%"PRIu64"\n", ull);      ull = ntoh64(&ull);     printf("%"PRIu64"\n", ull);      ull = hton64(&ull);     printf("%"PRIu64"\n", ull);      return 0; } 

Will show the following output:

1 72057594037927936 1 

You can test this with ntohl() if you drop the upper 4 bytes.

Also You can turn this into a nice templated function in C++ that will work on any size integer:

template <typename T> static inline T hton_any(const T &input) {     T output(0);     const std::size_t size = sizeof(input);     uint8_t *data = reinterpret_cast<uint8_t *>(&output);      for (std::size_t i = 0; i < size; i++) {         data[i] = input >> ((size - i - 1) * 8);     }      return output; } 

Now your 128 bit safe too!

like image 30
user442585 Avatar answered Sep 29 '22 12:09

user442585