当前位置: 首页 > 知识库问答 >
问题:

为什么16位和32位整数的有符号和无符号加法转换不同?

司寇嘉茂
2023-03-14

GCC和Clang似乎对有符号整数和无符号整数之间的加法有不同的解释,这取决于它们的大小。为什么会这样?所有编译器和平台上的转换是否一致?

举个例子:

#include <cstdint>
#include <iostream>

int main()
{

    std::cout <<"16 bit uint 2 - int 3 = "<<uint16_t(2)+int16_t(-3)<<std::endl;
    std::cout <<"32 bit uint 2 - int 3 = "<<uint32_t(2)+int32_t(-3)<<std::endl;
    return 0;
}

结果:

$ ./out.exe   
16 bit uint 2 - int 3 = -1
32 bit uint 2 - int 3 = 4294967295

在这两种情况下,我们得到了-1,但其中一个被解释为无符号整数和下溢。我本以为两者都会以同样的方式转化。

那么,为什么编译器会以如此不同的方式转换它们,这保证了一致性吗?我用G11.1.0和Clang12.0测试了这个。以及Arch Linux和Debian上的g 11.2.0,得到了相同的结果。

共有3个答案

冷宏茂
2023-03-14

16位无符号整数可以提升为32位整数,而不会由于范围差异而丢失任何值,因此会发生这种情况。32位整数并非如此。

贺光华
2023-03-14

那么,为什么编译器转换这些如此不同,

[语言律师]的标准语录:

[expr.arith.conv]

许多期望操作数为算术或枚举类型的二进制运算符会导致转换,并以类似的方式生成结果类型。其目的是生成一个公共类型,这也是结果的类型。这种模式被称为通常的算术转换,其定义如下:

  • ...
  • 否则,整数提升([conv.prom])应在两个操作数上执行。然后以下规则应适用于提升的操作数:
    • 如果两个操作数具有相同的类型,则不需要进一步转换。
    • 否则,如果两个操作数都有符号整数类型或都有无符号整数类型,则具有较小整数转换秩类型的操作数应转换为具有较大秩的操作数类型。
    • 否则,如果具有无符号整数类型的操作数的秩大于或等于其他操作数类型的秩,则具有有符号整数类型的操作数应转换为具有无符号整数类型的操作数的类型。
    • 否则,如果有符号整数类型的操作数的类型可以表示无符号整数类型的操作数类型的所有值,则无符号整数类型的操作数应转换为有符号整数类型的操作数类型。
    • 否则,两个操作数都应转换为与有符号整数类型的操作数类型相对应的无符号整数类型。

    [conv.prom]

    整数转换秩([conv.rank])小于int的秩的bool、char8_t、char16_t、char32_t或wchar_t以外的整数类型的prvalue可以转换为int类型的prvalue,如果int可以表示源类型的所有值;否则,源prvalue可以转换为无符号int类型的prvalue。

    这些转换被称为积分促销。

    std::uint16_t类型的转换秩可能低于int,在这种情况下,当用作操作数时,它将被提升int可能能够代表std::uint16_t的所有值,在这种情况下,升级将是int。两个int的常见类型是int

    std::uint32_t类型的转换等级可能与int相同或更高,在这种情况下,它不会被提升。无符号类型和具有相同秩的有符号类型的公共类型是无符号类型。

    有关为什么选择这种转换行为的解释,请参阅"国际标准的基本原理-编程语言-C"的章节"6.3.1.1布尔值、字符和整数"。我不会在这里引用整个章节。

    这保证是一致的吗?

    一致性取决于实现定义的整数类型的相对大小。

臧兴学
2023-03-14

当您执行uint16_t(2)int16_t(-3)时,两个操作数都是小于int的类型。正因为如此,每个操作数都被提升为int有符号的有符号的结果是一个有符号的整数,您会得到存储在该有符号整数中的-1的结果。

当您执行uint32_t(2)int32_t(-3)时,由于两个操作数都是int或更大的大小,因此不会发生转换,现在您处于有无符号有符号的情况,这会导致无符号整数,并且-1unsign值包装为可表示的最大值。

 类似资料:
  • 问题内容: 我有一个byte [4],其中包含一个32位无符号整数(按大端顺序),我需要将其转换为long(因为int无法保存无符号数字)。 另外,我该如何做相反(即从包含32位无符号整数的long到byte [4])呢? 问题答案: 听起来像是ByteBuffer的工作。 有点像

  • 在这个答复中, zwol提出了这样的主张: 将两个字节的数据从外部源转换为16位有符号整数的正确方法是使用以下帮助函数: 上述哪个函数是合适的取决于数组是否包含小端或大端表示。Endianness不是这里的问题,我想知道为什么zwol从转换为的值中减去。 为什么这是正确的方法? 转换为返回类型时如何避免实现定义的行为? 既然可以假设2的补码表示,那么这个更简单的强制转换将如何失败:

  • 精明的加法学专家会注意到,它只能加到62位。我在编译器和芯片设计方面的经历告诉我,保留位值黄金。所以我们有两个(设置为零)。 那么这是否意味着: 问题一: ~表示36位移位,包含10位类型Id和其余36位本地Id: #00000000000000000000# ShardID 3429的 二进制=1101 0110 0101 因此(hashedValue>>46)=00000 0 110 1 01

  • 我的目标是了解两者的互补性。 有符号整数中的等于。但是,如果您使用十六进制的或十进制的按位与它,它将等于。 在我看来,这不应该发生,因为顶部字节与结果字节相同 我的预期结果是该值不应该改变,它等于< code>-121。 我的实际结果是值发生变化。 我的猜测是,是一个。因此,顶部字节的有符号位和下部字节的无符号位将导致无符号位。但是......那不可能是对的。

  • 问题内容: 试图回答另一篇有关其解决方案涉及IP地址和网络掩码的文章时,我陷入了普通的按位算法。 在Python中,是否存在一种标准的方式来进行按位AND,OR,XOR,NOT运算,假设输入是“ 32位”(可能是负数)整数或long,并且结果必须是[[0,2 ** 32]? 换句话说,我需要一个与无符号长整数之间的C按位运算有效的Python对应物。 编辑:具体问题是这样的: 问题答案: 您可以通

  • 我快速浏览了C 03标准,但仍然无法判断这种行为是否有保证: 结果是: VC在32位窗口中给出<code>0xffffffff。但我的假设是,转换可以通过两种方式进行: 1) 8位有符号字符-1首先直接转换为8位无符号值,该值为二进制11111111或十进制255,然后扩展为32位无符号整数,给出255(0xff)。 2)8位有符号字符-1被有符号扩展到32位有符号int,给出0xffffffff