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.
You can specify that an integer literal (constant) should be interpreted as a long int
by adding the L
suffix (or a lowercase l
- but this looks too much like a 1
for my comfort). Similarly, for a long long int
, add the LL
suffix.
In the case of your macros, you will also need to explicitly cast the arguments, a
, b
and c
to the appropriate (long
or long long
) type.
However, rather than relying on a particular compiler to implement long int
as a 64-bit type (many compilers do not, and use 32-bits for both int
and long int
, and require long long int
for a 64-bit type), you should use the bit-width specific types defined in the <stdint.h>
header file.
Thus, the following code should be warning-free and portable:
#include <stdint.h>
typedef int64_t Triple;
#define TR_A(o) ((int32_t)(((int64_t)(o) & 0x7FFFFC0000000000LL) >> 42))
#define TR_B(o) ((int32_t)(((int64_t)(o) & 0x000003FFFFE00000LL) >> 21))
#define TR_C(o) ((int32_t)((int64_t)(o) & 0x00000000001FFFFFLL))
// EDIT/NOTE: I have changed the bitwise & operations to | in the macro below,
// as this is probably what you actually want (otherwise it will give 0 always)!
#define MK_TR(a,b,c) ((int64_t)(((int64_t)(a) << 42) | ((int64_t)(b) << 21) | (int64_t)(c)))
Also, it is very good practice to always include your macro arguments in parentheses (such as (c)
in the last line, above). Without this, a call to your macro with an expression as an argument can give you unexpected results, which can be difficult to track down. This would be a case in point:
int a = 1, b = 2, c = 3;
Triple test = MK_TR(a + 1, b + 1, c + 1); // Unexpected(?) result.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With