1

我有 2 个内核,一个是 32 位的,另一个是 64 位的。

在 64 位机器上,我支持 unsigned long long,我需要将此值分配给将在 32 位机器中访问的变量,例如:-

typedef struct {
    unsigned int low;
    unsigned int high;
} myint64_t;

myint64_t app_sc;

下面是 64 位机器的代码片段:

unsigned long long sc;

/* Calculate sc */
...

现在在 64 位机器上,我需要将“sc”分配给 app_sc,并将其用于 64 位机器上的一些计算。

我试图做这样的事情: -

app_sc = sc;

但是编译器给了我编译时错误。我可以类似地做这样的事情:-

 app_sc.low = sc & 0xFFFFFFFF;
 app_sc.high = (sc>>32) & (0xFFFFFFFF);

但这能保证它在所有情况下都有效吗?

有没有更好的方法呢?

4

5 回答 5

5

使用不太旧的编译器支持相当新的 C 标准(可能是 C99,甚至更早),您应该有一个<stdint.h>标头,为您提供类似int64_t(对于有符号 64 位整数)或uint64_t(对于无符号 64 位整数)的类型,这正是64 位,即使在 32 位机器上也是如此。

如果您的编译器没有它,我强烈建议升级您的编译器。你可能会使用GCC(除非你有一个非常奇怪的目标架构,GCC 不支持)。最新的 GCC 版本是 4.7。

请注意,32 位机器上的 64 位算术实际上需要一些编译器支持才能相当有效。(例如使用带有进位指令的add)。它不能只通过一个库来完成,即使需要一个库来提供最复杂的操作(例如 32 位机器上的 64 位除法)。换句话说,对于 32 位机器,快速 64 位算术不能在 C 中可移植地编码。

对于更大的数字,考虑使用任意精度的数字(称为 bigints),例如通过 GNU gmp库。这样的库使用非平凡的算法(所以即使是数学也很困难,你可以阅读关于它们的整本书并通过发明一个有竞争力的 bigint 实现来获得博士学位)。

于 2012-07-17T17:16:54.013 回答
3

首先,我同意尽可能使用stdint类型的建议,所以我会自己这样做。

其次,我能想到的唯一可能更便宜的转换方式是通过联合,比如

union Int64
{
    uint64_t val64;
    struct {
        uint32_t lo32;
        uint32_t hi32;
    };
};

union Int64 i64;
i64.val64 = sc;
app_sc.low = i64.lo32;
app_sc.high = i64.hi32;

注意事项

  • 如果这样做涉及存储和重新加载(如图所示),它可能比您的按位操作更昂贵
    • 如果您可以将现有app_sc的转换为该联合的实例(跳过 32 位加载),那么这可能是值得的
  • 或者,如果sc已经真正存储在内存中的某个位置,您可以将其地址转换为(union Int64 *)
    • 当然,如果sc当前分配了一个寄存器并且是脏的,那么获取地址可能会强制存储
  • 原则上可能存在包装和对齐问题,无论是现在还是随后的一些 ABI
  • 这取决于架构,因此后续端口可能意味着更改联合(我假设上面的 x86 little-endianness)

坦率地说,它很脆弱,正如我希望警告显示的那样。不过,这是另一种方法,您可以决定它是否也适合您的情况。

于 2012-07-17T18:00:22.790 回答
1

您的编译器,即使在 32 位机器上,也可能支持“long long int”。试试看?

于 2012-07-17T16:44:02.020 回答
1

您可以使用头文件 stdint.h 来使用有符号/无符号变量 uint64_t/int64_t/...uint8_t/int8_t 以获得更好的解释:http ://pubs.opengroup.org/onlinepubs/007904975/basedefs/stdint.h.html

于 2012-07-17T17:28:49.350 回答
0

在 32 位和 64 位架构中,改变的是指针的大小,因此 unsigned long long 在 32 位中的工作方式与在 64 位中的工作方式相同。

于 2012-07-17T16:48:41.163 回答