【问题标题】:How can you safely convert an unsigned long int to an unsigned int? [closed]如何安全地将 unsigned long int 转换为 unsigned int? [关闭]
【发布时间】:2021-11-22 13:06:40
【问题描述】:

我有一些 C 代码。在其中,我有一个无符号长整数形式的 64 位值。我想将其转换为 2 个不同的 32 位值。如何安全地做到这一点?这是我的第一次尝试:

char buff[16];
unsigned long int long_number;
unsigned int long_number_hi32;
unsigned int long_number_lw32;
long_number = 0x0123456789ABCDEFul;
long_number_hi32 = (unsigned int)(long_number >> 32);
long_number_lw32 = (unsigned int)(long_number >> 0);
kwrite("0x");
// This is a custom itoa function with params:
// (number (32-bit integer), buffer_ptr, buffer_length, base, pad_to_min_length)
itoa(long_number_hi32, buff, 16, 16, 8);
kwrite(buff);
itoa(long_number_lw32, buff, 16, 16, 8);
kwrite(buff);
kwrite("\n");

但是我得到的输出是:

0x01234567FFFFFFFF89ABCDE

检查组件,发现问题:

LUI   a0,0x01234
ADDI  a0,a0,1383
# ...
# Call itoa
# Call kwrite
LUI   a0,0x89abd
ADDI  a0,a0,-529
# ...
# Call itoa
# Call kwrite

在 64 位 RISC-V 汇编中,LUI 符号扩展提供的 20 位立即数,将目标寄存器的高 32 位设置为立即数的第 20 位。因此,寄存器 a0 以 0xFFFFFFFF89ABCDEF 结尾。我希望我的结果在 'E' 处被截断,以防止我的缓冲区溢出,方法是将 NULL 终止符放在我的 'F' 本来的位置。

我要补充一点,我的代码看起来与我提供的示例不完全相同,因为我已将 uint32_t、uint64_t、int32_t 和 int64_t 类型定义为 unsigned int、unsigned long int、signed int 和signed long int 类型的构建分别。我只是用内置类型代替了示例。

这应该如何在 C 中完成以确保可移植性正确?我必须使用工会吗?除了工会还有其他安全的方法吗?

【问题讨论】:

  • 你的itoa函数是做什么的?我怀疑它是为使用 signed 整数而设计的。
  • ... 在无符号整数不是的情况下,有符号整数往往会进行符号扩展
  • 我觉得自己很笨。你们是对的。我以为我已经对 itoa 函数进行了编码,如果给定一个基数,则将其视为无符号数!= 10。但是我在一年前编写了这个 itoa 函数并忘记了它实际上是以提供基数为负数的条件甚至不是一个完成的功能。我只是在查看它的源代码。很抱歉浪费了您的时间。
  • @EchelonX-Ray 没问题!这样的事情会发生。
  • 如果我将输入参数更改为无符号整数,它会按预期工作。

标签: c assembly riscv


【解决方案1】:

一些问题:

缓冲区不足

要形成像“FFFFFFFF89ABCDEF”这样的字符串buff[] 需要 17。

// char buff[16];
char buff[17]; 
// itoa(long_number_lw32, buff, 16, 16, 8);
itoa(long_number_lw32, buff, sizeof buff, 16, 8);

unsigned宽度

unsigned 可能是 16 位、32 位或更多。

对于此任务,请考虑 指定至少 32 的宽度。unsigned long, uint32least_t, uint32_t

// unsigned int long_number_lw32;
unsigned long long_number_lw32;

// long_number_lw32 = (unsigned int)(long_number >> 0);
long_number_lw32 = 0xFFFFFFFFu & long_number;

itoa() 未签名

我怀疑itoa() 是为int 结果和风险sign bit extension 而设计的。使用专为 unsigned tpyes 设计的功能,并且为此任务至少 32 位。


long:32 位还是 64 位?

long 只能是 32 位的。使用指定为足够宽的类型。 (至少 64 个)

// unsigned long int long_number;
unsigned long long long_number;
// long_number = 0x0123456789ABCDEFul;
long_number = 0x0123456789ABCDEFu; // l not needed

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多