c - 如何将 2 的补码转换为机器自然对应的带符号对应项?

标签 c language-lawyer unsigned unsigned-integer

<分区>

a 为有符号整数类型T 的变量,U 为相应的无符号类型。表达式 (U)a 产生的值对应于 a 的值的二进制补码表示形式为 U。我想知道 C 标准是否保证以下内容可以撤消该转换。是U 类型的u 并且具有(U)a 的值。是 MAX 类型 T 可以容纳的最大值。 (请注意到无符号类型的隐式转换,以及这些转换后带符号变量的每个正值都保持不变的事实。)

首先,假设T能够保存结果:

T convert_2scomplement_to_T(U n) {
    return n<=MAX ? n : -(T)(U)-n;
}

其次,假设函数应该检测到这样一个无效参数;是 MIN T 可以容纳的最小值:

T convert_2scomplement_to_T_checked(U n) {
    if(n <= MAX) return n;
    if( !(n & (U)1 << sizeof(U)*CHAR_BIT-1) ) { // (*)
        // invalid argument, the value is positive and `T' cannot hold it
    }
    /* `n' represents something negative if we're here. */
    if(-n < MIN) {
        // invalid argument, the value is negative and `T' cannot hold it
    }
    return -(T)(U)-n;
}

据我所知,标有//(*) 的行并不严格符合标准,因为标准不对符号位的位置做出任何保证。

所描述的功能是否按预期工作?在严格符合的代码中是否可以避免对符号位的检查?

(除了语言律师的事情……如果编写过代码的人知道至少有一个人在不使用二进制补码的平台上使用过它,并且可以发表评论,这是什么机器,那就太好了。 Wikipedia 提及

有符号的幅度:

补语:

但这在今天编写的程序中似乎没有什么可担心的。标准仍然适用于此类机器是否有原因?)

最佳答案

我认为这并不复杂。一个人的补码算法实际上更简单,因为每个数字都是其取反值的补码。唯一的问题是处理所有设置的位,因为它转换为负零。

所以是的,转换 S->U->S 绝对是可逆的,但 U->S->U 可能会因设置了高位的值而失败。而且您可能无法为负零撤消它,因为信息可能会丢失。

将有符号转换为无符号会保留位模式并且是空操作。

无符号到有符号必须处理设置了高位的数字。所有打开的位都是合法的,代表负零,允许陷阱,被视为零或强制为零(至少这是我的读数,但我手边没有 Univac 1100 无法尝试)。设置了高位的其他值在有符号范围之外,因此行为是实现定义的。它很可能会保留位模式,这是最简单的事情。

如果您正在寻找保证,您可能找不到。大部分 C/C++ 都是这样。

关于c - 如何将 2 的补码转换为机器自然对应的带符号对应项?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24543670/

相关文章:

c++ - 注入(inject)的类名作为类型

c - 乘法和除法无符号整数

c - 在Linux下,如何在C中的两个子进程之间共享缓冲区?

c - c + linux的练习

c++ - 实现一个没有未定义行为的类似 std::vector 的容器

c++ - 为什么 "for (i = 100; i <= 0; --i)"永远循环?

c++ - 有符号和无符号之间的减法,然后是除法

c - printf 运行在内核态还是用户态?

c - 将分隔的平面文件解析为结构的双向链表

c++ - 错误消息与命名右值引用混淆