将32位值分配给64位变量并保证前32位在C中为0的最佳方法

时间:2017-11-28 18:40:44

标签: c casting type-conversion bit-manipulation

我有一些C代码,它们具有int的变量,或者在一段时间内转换为int以便于使用(我们关心的是位值)。在这种情况下,Int将始终为32位。有时它们中的一些被分配给64位变量,有些是隐式的,有些是明确的:

long long 64bitfoo = 32bitbar;
long long 64bitfoo = (long long)32bitbar;

这在过去并不是一个问题,但最近我遇到了一个案例,在这个转换后,64位变量的前32位不是0.似乎某些特定版本的事件可以或多或少地填充垃圾的最高位(或者只是选择以前使用的存储位置而不是正确清除它)。这不会做,所以我正在寻找解决方案。

我可以做到这样的事情:

long long 64bitfoo = 32bitbar;
64bitfoo &= ~0xFFFFFFFF00000000;

清除顶部位,这应该适用于我需要的东西,但我觉得有更好的选择。到目前为止,这只显示了使用隐式转换的值,所以我很好奇隐式和显式转换之间是否存在允许显式转换处理它本身的差异?(不幸的是,我现在可以'只需添加显式转换并进行测试,触发此操作的条件很复杂且不易复制,因此代码更改必须非常牢固而不是猜测。)

我确定可能还有其他选项,做一些事情,而不仅仅是使用=来设置值,一种不同的方法来清除前32位更好,或某种方式设置初始值64如果只设置了最低位,则保证最高位保持清零的位值(64位变量有时会为其分配其他64位变量,因此它不能始终将最高位强制为0)。在搜索时没有找到很多东西,但这似乎不是很多。

编辑:我忘了提到有些情况下签名并不像是问题。一个例子是初始值是0xF8452370,然后long long值显示为-558965697074093200,即0xF83E27A8F8452370。因此,底部32位是相同的,但前32位不仅仅是1,而是1和0的散射。根据我的理解,没有理由签名与未签名的人会这样做(所有1'确定),但我肯定会弄错。

此外,我认为需要对64位变量进行签名,因为在其他情况下,它需要的值需要为负数或正数(实际整数)vs这些实例中只需要跟踪位值。它是一个非常多用的变量,我没有能力使它不能多次使用。

edit2:我很有可能在这里提出错误的问题,试图密切注意这一点。但是我在限制范围内工作,所以实际的问题可能是别的,我可能只是暂时加入一个绑带。快速破解是这样的:

  1. 有一个64位变量很长(或某些系统上的__int64,但在我遇到它的实例中应该总是很长)。我不能改变它是什么,或使它无符号。

  2. 我有一个返回32位内存地址的函数。我需要将该32位内存地址(不是指针,而是内存位置的实际值)分配给这个64位变量。

  3. 在这些情况下,我需要将64位变量的前32位设为0,将底部32位与原始值相同。有时它们不是0,但它们并不总是1。

  4. 因为我无法将64位变量更改为无符号,我认为我的最佳选择是手动清除前32位,并且正在寻找最佳方法

2 个答案:

答案 0 :(得分:4)

您正在进行符号扩展 - 将负符号值转换为更大的类型会将原始值的符号位“扩展”为新类型的所有高位,以便保留数值。例如,(int8_t) 0xFC = -4会转换为(int16_t) 0xFFFC = -4。额外的位不是“垃圾”;他们有非常具体的目的和意义。

如果你想避免这种情况,请使用无符号类型。例如:

long long sixtyfourbits = (unsigned int) thirtytwobits;

作为一个侧面点,我建议您在整个代码中使用<stdint.h>整数类型,如果您关心它们的大小 - 例如,使用int64_t代替long longuint32_t代替unsigned int。名称将更清楚地表明您的意图,并且有些平台对标准C类型使用不同的大小。 (例如,AVR微控制器使用16位int。)

答案 1 :(得分:0)

“联盟”是C语言解决此问题的自然方式。

typedef union {
    struct {
        int low;    // low 32 bits
        int high;   // high 32 bits 
    } e;            // 32bits mimic x86 CPU eax 
    __int64 r;      // 64bits mimic x86 CPU rax 
} Union64;
Union64 data; 
data.r = 0x1122334455667788;

则data.e.high将为0x11223344 和data.e.low将为0x55667788

反之亦然

data.e.high = 0xaabbccdd;
data.e.low  = 0x99eeff00;

然后data.r将为0xaabbccdd99eeff00

以您的情况

data.r = 0; // guarantee data.e.high is cleared
data.e.low = 32bitbar; // say 0x11223344

然后data.r将为0x0000000011223344;

这正是联合的目的。