在宏(或其他东西)中指定 int 大小

Specify int size in macro (or something)

我正在尝试使用这些宏将 3 个整数(即每个 21 位)存储在一个 long int 中:

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))

所以思路是o是64位,abc各是32位。 o里面存放的时候是21位,64位是空位,ab,然后是c

我遇到了一堆这样的错误:

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

是否可以在 TR_A/TR_B/TR_C 中添加一些内容来指定 o 是长的?

有更好的方法吗?

我希望能够 return 这些作为简单的值,而不是指针。在 PC 上使用 Linux。

您可以通过添加 L 后缀(或小写 l - 但这看起来太像1 为了我的安慰)。同样,对于 long long int,添加 LL 后缀。

对于您的宏,您还需要将参数 abc 显式转换为适当的(longlong long) 类型。

然而,而不是依靠特定的编译器将 long int 实现为 64 位类型(许多编译器不这样做,int 和 [=12= 都使用 32 位],并且要求 long long int 用于 64 位类型),您应该使用 <stdint.h> 头文件中定义的位宽 specific 类型。

因此,下面的代码应该没有警告并且可移植

#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)))

此外,始终将宏参数包含在括号中是非常好的做法(例如上面最后一行中的 (c))。否则,使用 expression 作为参数调用您的宏可能会给您带来意想不到的结果,这可能很难追踪。这就是一个很好的例子:

int a = 1, b = 2, c = 3;
Triple test = MK_TR(a + 1, b + 1, c + 1); // Unexpected(?) result.

要支持 +/- 1M 范围内的二进制补码有符号整数,需要屏蔽和移位:

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)

拆分时,需要恢复12位符号位:

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