views:

2858

answers:

9

I need to write a function to convert big endian to little endian in C. I can not use any library function.

A: 

for all your bit twiddling needs
http://graphics.stanford.edu/~seander/bithacks.html

Chris H
Nifty bit manipulation snippets. In this situation, however, the OP will need a simple bytes swapping logic.
mjv
Good page for researching bit hacks, but doesn't answer his specific question
Sam Post
A: 

for 16 bit values

unsigned short wBigE = value;
unsigned short wLittleE = ((wBigE & 0xFF) << 8) | (wBigE >> 8);

for 32 bit values

unsigned int   iBigE = value;
unsigned int   iLittleE = ((iBigE & 0xFF) << 24)
                        | ((iBigE & 0xFF00) << 8)
                        | ((iBigE >> 8) & 0xFF00)
                        | (iBigE >> 24);

This isn't the most efficient solution unless the compiler recognises that this is byte level manipulation and generates byte swapping code. But it doesn't depend on any memory layout tricks and can be turned into a macro pretty easily.

John Knoeller
+5  A: 
Sam Post
+2  A: 

Edit: These are library functions. Following them is the manual way to do it.

I am absolutely stunned by the number of people unaware of __byteswap_ushort, __byteswap_ulong, and __byteswap_uint64. Sure they are Visual C++ specific, but they compile down to some delicious code on x86/IA-64 architectures. :)

Here's an explicit usage of the bswap instruction, pulled from this page. Note that the intrinsic form above will always be faster than this, I only added it to give an answer without a library routine.

uint32 cq_ntohl(uint32 a) {
    __asm{
        mov eax, a;
        bswap eax; 
    }
}
280Z28
For a C question, you're suggesting something that's specific to Visual C++?
Alok
@Alok: Visual C++ is a product by Microsoft. It works just fine for compiling C code. :)
280Z28
Why does it stun you that many people aren't aware of Microsoft-specific implementations of byteswapping?
dreamlax
@dreamlax: Because I've worked in commercial environments that use Visual Studio as the official IDE for the better part of a decade at quite a few companies (contract work).
280Z28
Cool, that's good info for anyone developing a closed source product which doesn't need to be portable or standards compliant.
Sam Post
@280Z28: OK, but I think that the question is more general than your answer, and I hope you agree. Not that the question is very good to begin with :-)
Alok
@280Z28: I guess non-portable methods of byteswapping has been a very common task at the places you have worked.
dreamlax
the question says no library functions
John Knoeller
@John Knoeller: which is why I added the manual implementation. :) It says no library functions but doesn't rule out inline assembly.
280Z28
@280z28: can't beat bswap. If you are going to go MS specific, might as well go whole hog `uint32 __fastcall(uint32 a) { __asm { mov eax, edx; bswap eax; } }`
John Knoeller
@John Knoeller: the intrinsics *annihilate* the performance of that call, which is why I didn't bother to do anything past what's up there.
280Z28
A: 

As a joke:


#include <stdio.h>

int main (int argc, char *argv[])
{
    size_t sizeofInt = sizeof (int);
    int i;

    union
    {
        int x;
        char c[sizeof (int)];
    } original, swapped;

    original.x = 0x12345678;

    for (i = 0; i < sizeofInt; i++)
        swapped.c[sizeofInt - i - 1] = original.c[i];

    fprintf (stderr, "%x\n", swapped.x);

    return 0;
}
dreamlax
+1  A: 
Michael J
you can use xorSwap for better performance. Prefer this generic version above all the size specific ones...
ufotds
I tested it, it turns out this is faster than xorSwap... on x86.http://stackoverflow.com/questions/3128095/best-way-to-test-code-speed-in-c-without-profiler-or-does-it-not-make-sense-to
ufotds
A: 

If you want to change the endianess of a memory block you can use my blazingly fast approach. Your memory array should have a size that is a multiple of 8.

void ChangeMemEndianness(uint64_t *mem, size_t size) 
{
uint64_t m1 = 0xFF00FF00FF00FF00ULL, m2 = m1 >> CHAR_BIT;

size = (size + (sizeof (uint64_t) - 1)) / sizeof (uint64_t);
for(; size; size--, mem++)
  *mem = ((*mem & m1) >> CHAR_BIT) | ((*mem & m2) << CHAR_BIT);
}

This kind of function is useful for changing the endianess of Unicode UCS-2/UTF-16 files.

tristopia
A: 
#include <stdint.h>


//! Byte swap unsigned short
uint16_t swap_uint16( uint16_t val ) 
{
    return (val << 8) | (val >> 8 );
}

//! Byte swap unsigned short
int16_t swap_int16( int16_t val ) 
{
    return (val << 8) | ((val >> 8) & 0xFF);
}

//! Byte swap unsigned int
uint32_t swap_uint32( uint32_t val )
{
    val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF ); 
    return (val << 16) | (val >> 16);
}

//! Byte swap int
int32_t swap_int32( int32_t val )
{
    val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF ); 
    return (val << 16) | ((val >> 16) & 0xFFFF);
}
chmike
A: 

Will this work / be faster?

uint32_t swapped, result;

((byte*)&swapped)[0] = ((byte*)&result)[3];

((byte*)&swapped)[1] = ((byte*)&result)[2];

((byte*)&swapped)[2] = ((byte*)&result)[1];

((byte*)&swapped)[3] = ((byte*)&result)[0];

Paul
I think you mean `char`, not `byte`.
dreamlax