Search code examples
ctypes64-bitbitbit-shift

Specify int size in macro (or something)


I'm trying to store 3 integers (ie 21 bits each) in one long int with these macros:

typedef long int Triple;
#define TR_A(o) ((int)((o & 0x7FFFFC0000000000) >> 42))
#define TR_B(o) ((int)((o & 0x000003FFFFE00000) >> 21))
#define TR_C(o) ((int)(o & 0x00000000001FFFFF))
#define MK_TR(a,b,c) ((long int)((a<<42) & (b<<21) & c))

So the idea is that o is 64 bits, and a,b,c are 32 each. When stored inside o they are 21 bits, and the 64 bits are empty bit, a, b, and then c.

I get a bunch of these errors:

warning: left shift count >= width of type [-Wshift-count-overflow]
 #define MK_TR(a,b,c) ((long int)((a<<42) & (b<<21) & c))
                                    ^

Is it possible to add something to TR_A/TR_B/TR_C that specifies that o is long?

Any better way to do this?

I want to be able to return these as simple values, not pointers. Using Linux on PC.


Solution

  • To support two's complement signed ints in the range +/- 1M, both masking and shifting are required:

    inline uint64_t make64(int a, int b, int c) {
        return ((uint64_t) (a & 0x1fffff) << 42) |
               ((uint64_t) (b & 0x1fffff) << 21) |
               ((uint64_t) c & 0x1fffff)
    

    When splitting, the 12 sign bits will need to be restored:

    inline int32_t get_a(uint64_t t) {
        return (int32_t)((t >> 42 & 0xfffff) | (t & 0x4000000000000000) ? 0xfff00000 : 0);
    etc.