Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 527
Tomas By Avatar asked Oct 15 '25 06:10

Tomas By


1 Answers

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.
like image 168
Adrian Mole Avatar answered Oct 16 '25 22:10

Adrian Mole



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!