[TriLUG] Ten Little ENDIANS
Brian Weaver
weave at oculan.com
Mon Mar 24 15:34:49 EST 2003
This routine should byte swap a 64-bit number from little endian to big
endian, and back again.
The basics are to swap long[0] with long[1] and then perform a ntohl on
each.
long long swap_64(register long long val)
{
register long tmp = *((long *)&val);
*((long *)&val) = *((long *)&val + 1);
*((long *)&val + 1) = tmp;
*((long *)&val) = ntohl(*((long *)&val));
*((long *)&val + 1) = ntohl(*((long *)&val + 1);
return val;
}
it could be done without additional function calls using something like
the function below. It should loop 4 times. You could take the loop
logic out if you so inclined.
long long swap_64(register long long val)
{
register unsigned char *p = (unsigned char *)&val;
register unsigned char *q = (unsigned char *)&val + sizeof(long long) -
1;
register unsigned char xchg;
do
{
xchg = *p;
*p = *q;
*q = xchg;
} while(++p < --q);
return val;
}
-Weave
On Mon, 2003-03-24 at 10:19, Tarus Balog wrote:
> Gang:
>
> I need some help with C on Solaris/Intel. Since this post is long and
> slightly off-topic, feel free to hit delete now.
>
> OpenNMS is written in Java, but because Java does not have an ICMP API
> (which is important in network management) one was written in C and is
> accessed via JNI.
>
> Processors come in two main types with respect to byte order. Those that
> list the most significant byte first are BIG_ENDIAN, whereas those that
> list the least significant byte first are LITTLE_ENDIAN. Network data is
> by default BIG_ENDIAN, regardless of the processor used.
>
> Most RISC processors, like the SPARC, are BIG_ENDIAN, whereas Intel
> processors are LITTLE_ENDIAN. This means that on Intel you have to swap
> bytes received from the network in order for them to make sense.
>
> We do this in the following code by creating a "network to host" macro.
> Most LITTLE_ENDIAN systems seem to support the conversion of "long"
> variable types, but don't seem to have macros for 64 bit "long long"
> variable types, so we create our own: ntohll (network to host long long)
> and htonll (host to network long long). Here's part of the code:
>
> #if defined(__LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN) ||
> defined(__LITTLE_ENDIAN__)
> # ifndef ntohll
> # if defined(__DARWIN__)
> # define ntohll(_x_) NXSwapBigLongLongToHost(_x_)
> # else
> # define ntohll(_x_) __bswap_64(_x_)
> # endif
> # endif
>
> For BIG_ENDIAN systems, it is just a null macro.
>
> Now, notice that on DARWIN (Mac OS X) there is already a function defined
> (where Ben Reed found it is beyond me as it is almost a googlewhack). On
> Linux the function is __bswap_64.
>
> So, my first try was to search for an equivalent function to __bswap_64 in
> Solaris. No such luck. The "swab" function has potential, but I can't seem
> to get it to work.
>
> Then my next attempt was to get the GNU byteswap.h code to work on
> Solaris/Intel. It compiles, but when I run it I get an undefined symbol
> error on "__udivdi3".
>
> This is supposed to be included in libgcc.a, which I now have symbolically
> linked all over the place. I am also using GNU's ld and as. But still it
> fails. Not being a C programmer, I am also confused by the fact that a
> grep for "udivdi" in libgcc on Linux returns a match, whereas is fails on
> Solaris/Intel. So I am not even sure my libgcc.a contains the function.
> (Yes, I am grasping a bit here).
>
> Has anyone else on the list run into a similar issue on Solaris/Intel? I
> would appreciate any suggestions (outside of basing the box and installing
> Linux [grin]).
>
> -T
>
> --
> Tarus Balog
> Consultant
> Sortova Consulting Group, http://www.sortova.com
> +1-919-696-7625
> tarus at sortova.com
>
>
>
> _______________________________________________
> TriLUG mailing list
> http://www.trilug.org/mailman/listinfo/trilug
> TriLUG Organizational FAQ:
> http://www.trilug.org/~lovelace/faq/TriLUG-faq.html
--
"Microsoft, where quality is job 1.1" -Anonymous
More information about the TriLUG
mailing list