Re: byteorder mess

Linus Torvalds (torvalds@transmeta.com)
Fri, 5 Dec 1997 11:14:52 -0800 (PST)


On 5 Dec 1997, Jes Sorensen wrote:
>
> This will work on little endian boxes, but it breaks on big endian.
> Example, with the new patch we get from
> linux/include/linux/byteorder_big_endian.h:
>
> #define __cpu_to_be32(x) ((__u32)(x))
>
> In linux/include/linux/byteorder_generic.h this is used for htonl():
>
> #define ___htonl(x) __cpu_to_be32(x)
> #define ___htons(x) __cpu_to_be16(x)
> #define ___ntohl(x) __be32_to_cpu(x)
> #define ___ntohs(x) __be16_to_cpu(x)
>
> #define htonl(x) ((unsigned long)___htonl(x))
>
> Which will simply turn into `x'. This will break libc if you build it
> against these headers!

Why? ((unsigned long)(__u32)(x)) is the _correct_ answer on a big-endian
machine. How could that break libc?

If libc internally tries to do the htonl() functions and the above breaks
the function declaration, then libc is _wrong_.

As mentioned earlier, htonl() has traditionally always been just the
identity macro on big-endian systems, so if libc can't handle it then libc
is broken pretty much by definition. But this should be easy to fix: when
libc wants to actually implement the functions internally, just add a

#undef htonl
#undef ntohl
...

to that particular file before doing the function defines.

I know libc does the above for other things like this (again, this is
"standard practice" for implementing functions that are hidden by defines:
it's commonly used for stdio etc where some things can be #defines but
also require to be available as functions), so I'm surprised if it is
indeed missing the #undef's for this particular case.

Linus