Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
This provides the endian conversion functions form endian.h on Windows, Linux, *BSD, and Mac OS X. You still need to use -std=gnu99 instead of -std=c99 for gcc. The functions might actually be macros. Functions: htobe16, htole16, be16toh, le16toh, htobe32, htole32, be32toh, le32toh, htobe64, htole64, be64toh, le64toh. License: I hereby put "port…
// "License": Public Domain
// I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like.
// In case there are jurisdictions that don't support putting things in the public domain you can also consider it to
// be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it
// an example on how to get the endian conversion functions on different platforms.
#ifndef PORTABLE_ENDIAN_H__
#define PORTABLE_ENDIAN_H__
#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__)
# define __WINDOWS__
#endif
#if defined(__linux__) || defined(__CYGWIN__)
# include <endian.h>
#elif defined(__APPLE__)
# include <libkern/OSByteOrder.h>
# define htobe16(x) OSSwapHostToBigInt16(x)
# define htole16(x) OSSwapHostToLittleInt16(x)
# define be16toh(x) OSSwapBigToHostInt16(x)
# define le16toh(x) OSSwapLittleToHostInt16(x)
# define htobe32(x) OSSwapHostToBigInt32(x)
# define htole32(x) OSSwapHostToLittleInt32(x)
# define be32toh(x) OSSwapBigToHostInt32(x)
# define le32toh(x) OSSwapLittleToHostInt32(x)
# define htobe64(x) OSSwapHostToBigInt64(x)
# define htole64(x) OSSwapHostToLittleInt64(x)
# define be64toh(x) OSSwapBigToHostInt64(x)
# define le64toh(x) OSSwapLittleToHostInt64(x)
# define __BYTE_ORDER BYTE_ORDER
# define __BIG_ENDIAN BIG_ENDIAN
# define __LITTLE_ENDIAN LITTLE_ENDIAN
# define __PDP_ENDIAN PDP_ENDIAN
#elif defined(__OpenBSD__)
# include <sys/endian.h>
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
# include <sys/endian.h>
# define be16toh(x) betoh16(x)
# define le16toh(x) letoh16(x)
# define be32toh(x) betoh32(x)
# define le32toh(x) letoh32(x)
# define be64toh(x) betoh64(x)
# define le64toh(x) letoh64(x)
#elif defined(__WINDOWS__)
# include <winsock2.h>
# include <sys/param.h>
# if BYTE_ORDER == LITTLE_ENDIAN
# define htobe16(x) htons(x)
# define htole16(x) (x)
# define be16toh(x) ntohs(x)
# define le16toh(x) (x)
# define htobe32(x) htonl(x)
# define htole32(x) (x)
# define be32toh(x) ntohl(x)
# define le32toh(x) (x)
# define htobe64(x) htonll(x)
# define htole64(x) (x)
# define be64toh(x) ntohll(x)
# define le64toh(x) (x)
# elif BYTE_ORDER == BIG_ENDIAN
/* that would be xbox 360 */
# define htobe16(x) (x)
# define htole16(x) __builtin_bswap16(x)
# define be16toh(x) (x)
# define le16toh(x) __builtin_bswap16(x)
# define htobe32(x) (x)
# define htole32(x) __builtin_bswap32(x)
# define be32toh(x) (x)
# define le32toh(x) __builtin_bswap32(x)
# define htobe64(x) (x)
# define htole64(x) __builtin_bswap64(x)
# define be64toh(x) (x)
# define le64toh(x) __builtin_bswap64(x)
# else
# error byte order not supported
# endif
# define __BYTE_ORDER BYTE_ORDER
# define __BIG_ENDIAN BIG_ENDIAN
# define __LITTLE_ENDIAN LITTLE_ENDIAN
# define __PDP_ENDIAN PDP_ENDIAN
#else
# error platform not supported
#endif
#endif
@scunningham

This comment has been minimized.

Copy link

@scunningham scunningham commented Jun 11, 2014

Very useful. Any chance you can include the license language in the .h itself?

@markwardle

This comment has been minimized.

Copy link

@markwardle markwardle commented Mar 24, 2015

Excellent. Going to use this.

@grodansparadis

This comment has been minimized.

Copy link

@grodansparadis grodansparadis commented May 28, 2015

Perfect, just what I was looking for. Will be used in the VSCP project (http://www.vscp.org)

@KubaKaszycki

This comment has been minimized.

Copy link

@KubaKaszycki KubaKaszycki commented Dec 18, 2015

Perfect. Will appear in the Kubux project (http://github.org/KubaKaszycki/kubux)

@blizzard4591

This comment has been minimized.

Copy link

@blizzard4591 blizzard4591 commented Dec 23, 2015

I had a problem on a machine running RHEL5, where a GLIBC v2.5 was installed. The macros or functions htobe16 and alike are only present in versions 2.9 and greater.

If you do not mind, please include the following changes:

Replace

#if defined(__linux__) || defined(__CYGWIN__)

#   include <endian.h>

with this:

#if defined(__linux__) || defined(__CYGWIN__)
/* Define necessary macros for the header to expose all fields. */
#   define _BSD_SOURCE 
#   define __USE_BSD
#   define _DEFAULT_SOURCE
#   include <endian.h>
#   include <features.h>
/* See http://linux.die.net/man/3/endian */
#   if !defined(__GLIBC__) || !defined(__GLIBC_MINOR__) || ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 9))) 
#       include <arpa/inet.h>
#       if defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN)
#           define htobe16(x) htons(x)
#           define htole16(x) (x)
#           define be16toh(x) ntohs(x)
#           define le16toh(x) (x)

#           define htobe32(x) htonl(x)
#           define htole32(x) (x)
#           define be32toh(x) ntohl(x)
#           define le32toh(x) (x)

#           define htobe64(x) (((uint64_t)htonl(((uint32_t)(((uint64_t)(x)) >> 32)))) | (((uint64_t)htonl(((uint32_t)(x)))) << 32))
#           define htole64(x) (x)
#           define be64toh(x) (((uint64_t)ntohl(((uint32_t)(((uint64_t)(x)) >> 32)))) | (((uint64_t)ntohl(((uint32_t)(x)))) << 32))
#           define le64toh(x) (x)
#       elif defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)
#           define htobe16(x) (x)
#           define htole16(x) ((((((uint16_t)(x)) >> 8))|((((uint16_t)(x)) << 8)))
#           define be16toh(x) (x)
#           define le16toh(x) ((((((uint16_t)(x)) >> 8))|((((uint16_t)(x)) << 8)))

#           define htobe32(x) (x)
#           define htole32(x) (((uint32_t)htole16(((uint16_t)(((uint32_t)(x)) >> 16)))) | (((uint32_t)htole16(((uint16_t)(x)))) << 16))
#           define be32toh(x) (x)
#           define le32toh(x) (((uint32_t)le16toh(((uint16_t)(((uint32_t)(x)) >> 16)))) | (((uint32_t)le16toh(((uint16_t)(x)))) << 16))

#           define htobe64(x) (x)
#           define htole64(x) (((uint64_t)htole32(((uint32_t)(((uint64_t)(x)) >> 32)))) | (((uint64_t)htole32(((uint32_t)(x)))) << 32))
#           define be64toh(x) (x)
#           define le64toh(x) (((uint64_t)le32toh(((uint32_t)(((uint64_t)(x)) >> 32)))) | (((uint64_t)le32toh(((uint32_t)(x)))) << 32))
#       else
#           error Byte Order not supported or not defined.
#       endif
#   endif
@blizzard4591

This comment has been minimized.

Copy link

@blizzard4591 blizzard4591 commented Jan 15, 2016

There is a second error: On Windows you include "sys/param.h", which does not exist (maybe on Cygwin, but not with MSVC).

For people using a CMake based approach, I would like to point you to my project: https://github.com/blizzard4591/cmake-portable-endian

It is loosely based on this, but also works if there is no system-based endian-switching support whatsoever.

@vi

This comment has been minimized.

Copy link

@vi vi commented Jan 16, 2016

Fails for Android NDK: error: 'be32toh' was not declared in this scope

@n1tehawk

This comment has been minimized.

Copy link

@n1tehawk n1tehawk commented May 3, 2016

Nice work, thank you! Happily adopted by the sunxi-tools project. - Regards, NiteHawk

@Rahul11111

This comment has been minimized.

Copy link

@Rahul11111 Rahul11111 commented May 27, 2016

Excellent work. Thank you!

@baz1

This comment has been minimized.

Copy link

@baz1 baz1 commented Aug 21, 2016

Seems very useful. I suggest some hand-written function instead of an error for non-recognized platforms ; less efficiency is always better than a code that does not compile for some reason.

@n1tehawk

This comment has been minimized.

Copy link

@n1tehawk n1tehawk commented Oct 5, 2016

@panzi
linux-sunxi/sunxi-tools#59 seems to indicate that FreeBSD should be treated like OpenBSD, instead of being the same as NetBSD and DragonFly...

Regards, NiteHawk

@n1tehawk

This comment has been minimized.

Copy link

@n1tehawk n1tehawk commented Oct 25, 2016

Side note: Using the winsock2 functions for the Windows platform (when BYTE_ORDER == LITTLE_ENDIAN) has the potential drawback of requiring applications to link against the corresponding library (-lws2_32).

@rhdunn

This comment has been minimized.

Copy link

@rhdunn rhdunn commented Dec 7, 2016

Nice work. I am using it in espeak-ng as a compatibility shim for endian.h.

@pcordes

This comment has been minimized.

Copy link

@pcordes pcordes commented Apr 26, 2017

According to this SO post and comments here, ntohl doesn't inline on Windows. It's a DLL call instead of a single asm instruction...

Since there's already an #ifdef branch explicitly for LITTLE_ENDIAN Windows, I'd suggest changing avoiding ntohl there.

Pkmx's fork of this gist has that change, using _byteswap_ulong(x) instead of ntohl for MSVC, and __builtin_bswap32(x) for GNU C (gcc, clang, icc).

@zhengqiangmemeda

This comment has been minimized.

Copy link

@zhengqiangmemeda zhengqiangmemeda commented May 25, 2017

@blizzard4591 ,How to solve the problem of lacking of "sys/param.h" which does not exis on Windows you? I would appreciate it if you can give me some guides

@denniswon

This comment has been minimized.

Copy link

@denniswon denniswon commented Aug 14, 2017

@zhengqianman did you resolve sys/param.h issue for windows visual studio? If you did, could you give me some tips on resolve it?

@sjlongland

This comment has been minimized.

Copy link

@sjlongland sjlongland commented Nov 13, 2017

Newlib toolchain users (other than Cygwin), you might want to have a look here:

https://gist.github.com/sjlongland/10642bf86d60bf3d9af04cf504f569da/revisions#diff-a5346b4ffac3d9b1da20a7d99957566f

@ao2

This comment has been minimized.

Copy link

@ao2 ao2 commented Mar 7, 2018

Hi,

the following change adds support for GNU Hurd, and may fix build failures in case portable_endian.h is used in software packaged for Debian, as Hurd is one of the official Debian build targets.

diff --git a/portable_endian.h b/portable_endian.h
index 99845d0..1f9f490 100644
--- a/portable_endian.h
+++ b/portable_endian.h
@@ -13,7 +13,7 @@

 #endif

-#if defined(__linux__) || defined(__CYGWIN__)
+#if defined(__linux__) || defined(__CYGWIN__) || defined(__GNU__)

 #      include <endian.h>

Ciao,
Antonio

@Kaiepi

This comment has been minimized.

Copy link

@Kaiepi Kaiepi commented Mar 16, 2018

The OpenBSD code should look like this:

#elif defined(__OpenBSD__)

#        include <endian.h>

#        define __BYTE_ORDER    BYTE_ORDER
#        define __BIG_ENDIAN    BIG_ENDIAN
#        define __LITTLE_ENDIAN LITTLE_ENDIAN
#        define __POP_ENDIAN    POP_ENDIAN

Instead of this:

#elif defined(__OpenBSD__)

#	include <sys/endian.h>
@AlexanderStohr

This comment has been minimized.

Copy link

@AlexanderStohr AlexanderStohr commented Mar 29, 2018

#elif defined(__WINDOWS__)

#	include <winsock2.h>
#	include <sys/param.h>

"sys/param.h is a unix/linux header-file, and you shouldn't expect to find that in your Windows system." (unless you are using a GNU compiler.)
https://stackoverflow.com/questions/18333651/vs2010-can-not-open-include-file-sys-param-h

@AlexanderStohr

This comment has been minimized.

Copy link

@AlexanderStohr AlexanderStohr commented Mar 29, 2018

to me it looks like this patch from 2014 adressed it already on the source tree of someone else:
PDAL/PDAL@c432437

(no idea who invented this first and who branched that "idea" from whom - at least the upstream connection seemingly is broken nowadays)

@AlexanderStohr

This comment has been minimized.

Copy link

@AlexanderStohr AlexanderStohr commented Mar 29, 2018

thinking again - your code might work perfectly for GNU C on the windows platform.
guess what - people are trying out to compile it with MSVC - and its just not documented that you were not targeting that compiler.

@proski

This comment has been minimized.

Copy link

@proski proski commented Feb 20, 2019

Defining __WINDOWS__ is not good. #ifdef __WINDOWS__ can work differently in files that include and don't include endian.h, which would be surprising. It's better to define symbols that communicate their limited scope, e.g. __ENDIAN_WINDOWS.
The use of __builtin_bswapNN whould be limited to the compiles that define it (GCC and Clang, both define __GNUC__).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.