diff --git a/test/uint.c b/test/uint.c index b8e87f3..b4d3f33 100644 --- a/test/uint.c +++ b/test/uint.c @@ -1,8 +1,8 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include int main() { char buf[8]; @@ -11,36 +11,38 @@ int main() { uint16 a; buf[0]=buf[1]=0; - uint16_pack_big(buf,0x1234); - assert(buf[0]==0x12 && buf[1]==0x34); + uint16_pack_big(buf,0xabcd); + assert((unsigned char)buf[0]==0xab && (unsigned char)buf[1]==0xcd); uint16_unpack_big(buf,&a); - assert(a==0x1234); - assert(uint16_read_big(buf)==0x1234); + assert(a==0xabcd); + assert(uint16_read_big(buf)==0xabcd); buf[0]=buf[1]=0; - uint16_pack(buf,0x1234); - assert(buf[0]==0x34 && buf[1]==0x12); + uint16_pack(buf,0xabcd); + assert((unsigned char)buf[0]==0xcd && (unsigned char)buf[1]==0xab); uint16_unpack(buf,&a); - assert(a==0x1234); - assert(uint16_read(buf)==0x1234); + assert(a==0xabcd); + assert(uint16_read(buf)==0xabcd); } { uint32 a; buf[0]=buf[1]=buf[2]=buf[3]=0; - uint32_pack_big(buf,0x12345678); - assert(buf[0]==0x12 && buf[1]==0x34 && buf[2]==0x56 && buf[3]==0x78); + uint32_pack_big(buf,0x89abcdef); + assert((unsigned char)buf[0]==0x89 && (unsigned char)buf[1]==0xab && + (unsigned char)buf[2]==0xcd && (unsigned char)buf[3]==0xef); uint32_unpack_big(buf,&a); - assert(a==0x12345678); - assert(uint32_read_big(buf)==0x12345678); + assert(a==0x89abcdef); + assert(uint32_read_big(buf)==0x89abcdef); buf[0]=buf[1]=buf[2]=buf[3]=0; - uint32_pack(buf,0x12345678); - assert(buf[0]==0x78 && buf[1]==0x56 && buf[2]==0x34 && buf[3]==0x12); + uint32_pack(buf,0x89abcdef); + assert((unsigned char)buf[3]==0x89 && (unsigned char)buf[2]==0xab && + (unsigned char)buf[1]==0xcd && (unsigned char)buf[0]==0xef); uint32_unpack(buf,&a); - assert(a==0x12345678); - assert(uint32_read(buf)==0x12345678); + assert(a==0x89abcdef); + assert(uint32_read(buf)==0x89abcdef); } { @@ -48,18 +50,18 @@ int main() { unsigned int i; byte_zero(buf,sizeof(buf)); - uint64_pack_big(buf,0x0102030405060708ull); - for (i=0; i<8; ++i) assert(buf[i]==i+1); + uint64_pack_big(buf,0x8182838485868788ull); + for (i=0; i<8; ++i) assert((unsigned char)buf[i]==i+0x81); uint64_unpack_big(buf,&a); - assert(a==0x0102030405060708ull); - assert(uint64_read_big(buf)==0x0102030405060708ull); + assert(a==0x8182838485868788ull); + assert(uint64_read_big(buf)==0x8182838485868788ull); byte_zero(buf,sizeof(buf)); - uint64_pack(buf,0x0102030405060708ull); - for (i=0; i<8; ++i) assert(buf[7-i]==i+1); + uint64_pack(buf,0x8182838485868788ull); + for (i=0; i<8; ++i) assert((unsigned char)buf[7-i]==i+0x81); uint64_unpack(buf,&a); - assert(a==0x0102030405060708ull); - assert(uint64_read(buf)==0x0102030405060708ull); + assert(a==0x8182838485868788ull); + assert(uint64_read(buf)==0x8182838485868788ull); } diff --git a/uint16.h b/uint16.h index d5a5aa7..c3ea2e9 100644 --- a/uint16.h +++ b/uint16.h @@ -14,42 +14,42 @@ typedef int16_t int16; #if (defined(__i386__) || defined(__x86_64__)) && !defined(NO_UINT16_MACROS) +/* On x86 and x64 unaligned access are OK and the compiler knows it and + * will collapse this long-looking code into a single load or store + * instruction, so turn it into inline functions */ + static inline void uint16_pack(char* out,uint16 in) { - *(uint16*)out=in; + out[0]=in; + out[1]=in>>8; } static inline void uint16_unpack(const char *in,uint16* out) { - *out=*(const uint16*)in; + const unsigned char* i = (const unsigned char*)in; + *out=i[0] | (i[1]<<8); } static inline uint16 uint16_read(const char* in) { - return *(const uint16*)in; + const unsigned char* i = (const unsigned char*)in; + return i[0] | (i[1]<<8); } -#if defined(__x86_64__) && defined(__GNUC__) - static inline void uint16_pack_big(char* out,uint16 in) { - *(uint16*)out=__builtin_bswap16(in); + out[0]=in>>8; + out[1]=in; } -static inline void uint16_unpack_big(const char in[2],uint16* out) { - *out=__builtin_bswap16(*(const uint16*)in); +static inline void uint16_unpack_big(const char *in,uint16* out) { + const unsigned char* i = (const unsigned char*)in; + *out=(i[0]<<8) | i[1]; } -static inline uint16 uint16_read_big(const char in[2]) { - return __builtin_bswap16(*(const uint16*)in); +static inline uint16 uint16_read_big(const char* in) { + const unsigned char* i = (const unsigned char*)in; + return (i[0]<<8) | i[1]; } #else -void uint16_pack_big(char *out,uint16 in); -void uint16_unpack_big(const char *in,uint16* out); -uint16 uint16_read_big(const char *in); - -#endif - -#else - void uint16_pack(char *out,uint16 in); void uint16_pack_big(char *out,uint16 in); void uint16_unpack(const char *in,uint16* out); diff --git a/uint32.h b/uint32.h index 79fdea7..4d2b69f 100644 --- a/uint32.h +++ b/uint32.h @@ -14,42 +14,46 @@ typedef int32_t int32; #if (defined(__i386__) || defined(__x86_64__)) && !defined(NO_UINT32_MACROS) +/* On x86 and x64 unaligned access are OK and the compiler knows it and + * will collapse this long-looking code into a single load or store + * instruction, so turn it into inline functions */ + static inline void uint32_pack(char* out,uint32 in) { - *(uint32*)out=in; + out[0]=in; + out[1]=in>>8; + out[2]=in>>16; + out[3]=in>>24; } static inline void uint32_unpack(const char *in,uint32* out) { - *out=*(const uint32*)in; + const unsigned char* i = (const unsigned char*)in; + *out=i[0] | (i[1]<<8) | (i[2]<<16) | (i[3]<<24); } static inline uint32 uint32_read(const char* in) { - return *(const uint32*)in; + const unsigned char* i = (const unsigned char*)in; + return i[0] | (i[1]<<8) | (i[2]<<16) | (i[3]<<24); } -#if defined(__x86_64__) && defined(__GNUC__) - static inline void uint32_pack_big(char *out,uint32 in) { - *(uint32*)out=__builtin_bswap32(in); + out[0]=in>>24; + out[1]=in>>16; + out[2]=in>>8; + out[3]=in; } static inline void uint32_unpack_big(const char *in,uint32* out) { - *out=__builtin_bswap32(*(const uint32*)in); + const unsigned char* i = (const unsigned char*)in; + *out=(i[0]<<24) | (i[1]<<16) | (i[2]<<8) | i[3]; } static inline uint32 uint32_read_big(const char *in) { - return __builtin_bswap32(*(const uint32*)in); + const unsigned char* i = (const unsigned char*)in; + return (i[0]<<24) | (i[1]<<16) | (i[2]<<8) | i[3]; } #else -void uint32_pack_big(char *out,uint32 in); -void uint32_unpack_big(const char *in,uint32* out); -uint32 uint32_read_big(const char *in); - -#endif - -#else - void uint32_pack(char *out,uint32 in); void uint32_pack_big(char *out,uint32 in); void uint32_unpack(const char *in,uint32* out); diff --git a/uint64.h b/uint64.h index 0db7a37..eb93eae 100644 --- a/uint64.h +++ b/uint64.h @@ -13,12 +13,61 @@ typedef uint64_t uint64; typedef int64_t int64; #if (defined(__i386__) || defined(__x86_64__)) && !defined(NO_UINT64_MACROS) -#define uint64_pack(out,in) (*(uint64*)(out)=(in)) -#define uint64_unpack(in,out) (*(out)=*(uint64*)(in)) -#define uint64_read(in) (*(uint64*)(in)) -void uint64_pack_big(char *out,uint64 in); -void uint64_unpack_big(const char *in,uint64* out); -uint64 uint64_read_big(const char *in); + +/* On x86 and x64 unaligned access are OK and the compiler knows it and + * will collapse this long-looking code into a single load or store + * instruction, so turn it into inline functions */ + +static inline void uint64_pack(char* out,uint64 in) { + out[0]=in; + out[1]=in>>8; + out[2]=in>>16; + out[3]=in>>24; + out[4]=in>>32; + out[5]=in>>40; + out[6]=in>>48; + out[7]=in>>56; +} + +static inline void uint64_unpack(const char *in,uint64* out) { + const unsigned char* i = (const unsigned char*)in; + *out=i[0] | (i[1]<<8) | (i[2]<<16) | ((uint64)i[3]<<24) | + ((uint64)i[4]<<32) | ((uint64)i[5]<<40) | + ((uint64)i[6]<<48) | ((uint64)i[7]<<56); +} + +static inline uint64 uint64_read(const char *in) { + const unsigned char* i = (const unsigned char*)in; + return i[0] | (i[1]<<8) | (i[2]<<16) | ((uint64)i[3]<<24) | + ((uint64)i[4]<<32) | ((uint64)i[5]<<40) | + ((uint64)i[6]<<48) | ((uint64)i[7]<<56); +} + +static inline void uint64_pack_big(char *out,uint64 in) { + out[0]=in>>56; + out[1]=in>>48; + out[2]=in>>40; + out[3]=in>>32; + out[4]=in>>24; + out[5]=in>>16; + out[6]=in>>8; + out[7]=in; +} + +static inline void uint64_unpack_big(const char *in,uint64* out) { + const unsigned char* i = (const unsigned char*)in; + *out=(i[7] | (i[6]<<8) | (i[5]<<16) | ((uint64)(i[4])<<24)) | + ((uint64)(i[3])<<32) | ((uint64)(i[2])<<40) | + ((uint64)(i[1])<<48) | ((uint64)(i[0])<<56); +} + +static inline uint64 uint64_read_big(const char *in) { + const unsigned char* i = (const unsigned char*)in; + return (i[7] | (i[6]<<8) | (i[5]<<16) | ((uint64)(i[4])<<24)) | + ((uint64)(i[3])<<32) | ((uint64)(i[2])<<40) | + ((uint64)(i[1])<<48) | ((uint64)(i[0])<<56); +} + #else void uint64_pack(char *out,uint64 in);