首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将32位值赋值给64位变量并保证前32位在C中为0的最佳方法

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

Stack Overflow用户
提问于 2017-11-28 18:40:43
回答 3查看 6.8K关注 0票数 1

我有一些C代码,这些变量要么是int,要么是为了便于使用而转换为int(我们关心的是位值)。在这种情况下,Int将始终是32位。其中一些被分配给64位变量,有些是隐式的,有些是显式的:

代码语言:javascript
复制
long long 64bitfoo = 32bitbar;
long long 64bitfoo = (long long)32bitbar;

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

我显然可以做这样的事:

代码语言:javascript
复制
long long 64bitfoo = 32bitbar;
64bitfoo &= ~0xFFFFFFFF00000000;

清除顶部的部分,这应该适用于我所需要的,但我觉得有更好的选择。到目前为止,这只显示在使用隐式强制转换的值上,因此我很好奇,隐式和显式转换之间是否存在允许显式强制转换来处理这个问题的区别?(不幸的是,我目前不能仅仅添加显式强制转换并进行测试,触发这种转换的条件非常复杂,不易复制,因此代码更改需要非常坚定,而不是猜测)。

我确信还可能有其他选项,不只是使用=来设置值,使用不同的方式清除前32位(更好),或者以某种方式设置初始64位值(如果只设置底部位,则保证顶部位保持清晰)( 64位变量有时会得到分配给它的其他64位变量,因此不可能在任何时候都强制将顶位强制为0)。在搜索的时候并没有发现很多东西,这似乎并不是什么经常发生的事情。

编辑:我忘了提到,在某些情况下,签名似乎并不是问题所在。一个例子是初始值为0xF8452370,然后长值为-558965697074093200,即0xF83E27A8F8452370。所以,下面的32位是相同的,但前32位不只是1,而是1和0的零散。据我所知,没有理由用符号和无符号的方式来做这件事(这是肯定的),但我肯定会弄错。

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

edit2:我很可能在这里问错了问题,试图关注这个问题。但是我是在限制范围内工作的,所以实际的问题可能是其他的问题,而且我现在可能只是被困在加了一个绷带。最简单的问题是:

  1. 有一个64位变量是长的(或者在某些系统上是__int64,但是在我遇到的情况下,它应该总是长的)。我不能改变它是什么,也不能使它没有签名。
  2. 我有一个函数返回32位内存地址。我需要将32位内存地址(不是作为指针,而是作为内存位置的实际值)分配给这个64位变量。
  3. 在这些情况下,我需要64位变量的前32位为0,底部32位与原始值相同。有时它们不是0,但它们并不总是1。
  4. 因为我不能将64位变量更改为无符号,我认为我的最佳选择是手动清除前32位,并且正在寻找最好的方法。
EN

回答 3

Stack Overflow用户

发布于 2017-11-28 18:47:45

您将遇到符号扩展--将负号值转换为更大的类型,将原始值的符号位“扩展”到新类型的所有上位,从而保留数字值。例如,(int8_t) 0xFC = -4转换为(int16_t) 0xFFFC = -4。额外的部分不是“垃圾”,它们有一个非常具体的目的和意义。

如果要避免这种情况,请使用无符号类型进行强制转换。例如:

代码语言:javascript
复制
long long sixtyfourbits = (unsigned int) thirtytwobits;

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

票数 5
EN

Stack Overflow用户

发布于 2017-11-28 19:05:37

我们关心的是比特值

然后,您应该远离签名的类型,并且始终使用无符号

当有符号(或无符号)类型转换为同一类型的更大大小时,将保留值,即19变为19,-19变为-19。

但是有符号类型并不总是通过在前面添加零来保持二进制模式,当从较小的类型转到更大的类型时,而无符号类型则这样做。

对于2的补码(符号类型最常见的表示形式),所有负值将是符号扩展,这意味着在前面添加ones而不是0

代码语言:javascript
复制
SIGNED:
8 bit:  -3 -> FD
16 bit: -3 -> FFFD
32 bit: -3 -> FFFFFFFD
64 bit: -3 -> FFFFFFFFFFFFFFFD

UNSIGNED:
8 bit:  253 -> FD
16 bit: 253 -> 00FD
32 bit: 253 -> 000000FD
64 bit: 253 -> 00000000000000FD

似乎某些特定版本的事件或多或少地会用垃圾填充顶部的位。

不,要么新的额外位将全部为零,要么它们都是1。

如果不是这样,您的系统就不符合C标准。

票数 4
EN

Stack Overflow用户

发布于 2020-09-16 00:35:49

“‘Union”是C语言中解决这个问题的自然方式。

代码语言:javascript
复制
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。

反之亦然

代码语言:javascript
复制
data.e.high = 0xaabbccdd;
data.e.low  = 0x99eeff00;

然后data.r将是0 xaabbccdd99eeff00。

在你的情况下

代码语言:javascript
复制
data.r = 0; // guarantee data.e.high is cleared
data.e.low = 32bitbar; // say 0x11223344

则data.r为0x0000000011223344;

这正是工会的目的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47538706

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档