diff options
author | Eric S. Raymond <esr@thyrsus.com> | 2009-03-13 12:04:42 +0000 |
---|---|---|
committer | Eric S. Raymond <esr@thyrsus.com> | 2009-03-13 12:04:42 +0000 |
commit | 21a5f024aada70c30acf3b81876cac9a85b3bb5f (patch) | |
tree | 215336e18c39fd16416725e826b48eb76c19d216 /bits.c | |
parent | 0dcad7b8b1ae3d5e9ed3ed9d0e6680b0f58daa25 (diff) | |
download | gpsd-21a5f024aada70c30acf3b81876cac9a85b3bb5f.tar.gz |
Sign-extend negative long longs correctly.
Diffstat (limited to 'bits.c')
-rw-r--r-- | bits.c | 40 |
1 files changed, 23 insertions, 17 deletions
@@ -8,6 +8,8 @@ */ #include <assert.h> +#define DEBUG + #include "bits.h" #ifdef DEBUG #include <stdio.h> @@ -15,12 +17,10 @@ #include "gpsd.h" #endif /* DEBUG */ - - #define BITS_PER_BYTE 8 unsigned long long ubits(char buf[], unsigned int start, unsigned int width) -/* extract a bitfield from the buffer as an unsigned big-endian long */ +/* extract a bitfield from the buffer as an unsigned big-endian long long */ { unsigned long long fld = 0; unsigned int i; @@ -31,25 +31,25 @@ unsigned long long ubits(char buf[], unsigned int start, unsigned int width) fld <<= BITS_PER_BYTE; fld |= (unsigned char)buf[i]; } -#ifdef DEBUG +#ifdef UDEBUG printf("Extracting %d:%d from %s: segment 0x%llx = %lld\n", start, width, gpsd_hexdump(buf, 12), fld, fld); -#endif /* DEBUG */ +#endif /* UDEBUG */ end = (start + width) % BITS_PER_BYTE; if (end != 0) { fld >>= (BITS_PER_BYTE - end); -#ifdef DEBUG +#ifdef UDEBUG printf("After downshifting by %d bits: 0x%llx = %lld\n", BITS_PER_BYTE - end, fld, fld); -#endif /* DEBUG */ +#endif /* UDEBUG */ } fld &= ~(0xffffffff << width); -#ifdef DEBUG +#ifdef UDEBUG printf("After selecting out the bottom %u bits: 0x%llx = %lld\n", width, fld, fld); -#endif /* DEBUG */ +#endif /* UDEBUG */ return fld; } @@ -57,16 +57,22 @@ unsigned long long ubits(char buf[], unsigned int start, unsigned int width) signed long long sbits(char buf[], unsigned int start, unsigned int width) /* extract a bitfield from the buffer as a signed big-endian long */ { - unsigned long long un = ubits(buf, start, width); - signed long long fld; + unsigned long long fld = ubits(buf, start, width); +#ifdef DEBUG + (void)fprintf(stderr, "sbits(%d, %d) extracts %llx\n", start, width, fld); +#endif /* DEBUG */ /*@ +relaxtypes */ - if (un & (1 << width)) - fld = -(un & ~(1 << width)); - else - fld = (signed long long)un; - - return fld; + if (fld & (1 << (width-1))) { +#ifdef DEBUG + (void)fprintf(stderr, "%llx is signed\n", fld); +#endif /* DEBUG */ + fld |= (-1LL << (width-1)); + } +#ifdef DEBUG + (void)fprintf(stderr, "sbits(%d, %d) returns %lld\n", start, width, (signed long long)fld); +#endif /* DEBUG */ + return (signed long long)fld; /*@ -relaxtypes */ } |