Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-apps-script/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C语言中的有符号到无符号的转换-总是安全的吗?_C_Type Conversion - Fatal编程技术网

C语言中的有符号到无符号的转换-总是安全的吗?

C语言中的有符号到无符号的转换-总是安全的吗?,c,type-conversion,C,Type Conversion,假设我有下面的C代码 unsigned int u = 1234; int i = -5678; unsigned int result = u + i; 这里正在进行什么隐式转换,对于u和i的所有值,该代码是否安全?(安全的,在这个意义上,即使本例中的结果将溢出到某个巨大的正数,我也可以将其转换回int并获得真实结果。)简短回答 您的i将通过添加UINT_MAX+1转换为无符号整数,然后使用无符号值进行加法,从而产生较大的结果(取决于u和i的值) 长答案 根据C99标准: 6.3.1.8常

假设我有下面的C代码

unsigned int u = 1234;
int i = -5678;

unsigned int result = u + i;

这里正在进行什么隐式转换,对于
u
i
的所有值,该代码是否安全?(安全的,在这个意义上,即使本例中的结果将溢出到某个巨大的正数,我也可以将其转换回int并获得真实结果。)

简短回答

您的
i
将通过添加
UINT_MAX+1
转换为无符号整数,然后使用无符号值进行加法,从而产生较大的
结果
(取决于
u
i
的值)

长答案

根据C99标准:

6.3.1.8常用算术转换

  • 如果两个操作数的类型相同,则无需进一步转换
  • 否则,如果两个操作数都具有有符号整数类型或都具有无符号整数类型,则整数转换秩较小的操作数类型将转换为秩较大的操作数类型
  • 否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则具有有符号整数类型的操作数将转换为具有无符号整数类型的操作数的类型
  • 否则,如果带符号整数类型的操作数类型可以表示带符号整数类型的操作数类型的所有值,则带符号整数类型的操作数将转换为带符号整数类型的操作数类型
  • 否则,两个操作数都将转换为与有符号整数类型的操作数类型相对应的无符号整数类型
  • 在您的例子中,我们有一个无符号int(
    u
    )和一个有符号int(
    i
    )。参考上面的(3),由于两个操作数具有相同的秩,因此需要将
    i
    转换为无符号整数

    6.3.1.3有符号和无符号整数

  • 当整数类型的值转换为除_Bool以外的其他整数类型时,如果该值可以用新类型表示,则该值不变
  • 否则,如果新类型是无符号的,则会通过重复地将新类型中可以表示的最大值加上或减去一个值来转换该值,直到该值在新类型的范围内
  • 否则,新类型已签名,且无法在其中表示值;要么结果是实现定义的,要么引发实现定义的信号
  • 现在我们需要参考上面的(2)。您的
    i
    将通过添加
    UINT\u MAX+1
    转换为无符号值。因此,结果将取决于实现中如何定义
    UINT\u MAX
    。它会很大,但不会溢出,因为:

    6.2.5(9)

    涉及无符号操作数的计算永远不会溢出,因为不能由结果无符号整数类型表示的结果将被减少为比结果类型可以表示的最大值大一的数的模

    奖金:算术转换半WTF

    #include <stdio.h>
    
    int main(void)
    {
      unsigned int plus_one = 1;
      int minus_one = -1;
    
      if(plus_one < minus_one)
        printf("1 < -1");
      else
        printf("boring");
    
      return 0;
    }
    

    由于上面描述的转换规则,无论系统的符号数字表示形式如何,这都保证是可移植的。有关更多信息,请参阅此SO问题:

    当添加一个无符号变量和一个有符号变量(或任何二进制操作)时,这两个变量都会隐式转换为无符号变量,在本例中,这将导致巨大的结果


    因此,从某种意义上讲,结果可能是巨大的、错误的,但它永远不会崩溃。

    当从有符号转换为无符号时,有两种可能性。最初为正的数字保留(或解释为)相同的值。原来为负数的数字现在将被解释为更大的正数。

    正如前面回答的,您可以在有符号和无符号之间来回转换,而不会出现问题。有符号整数的边界大小写为-1(0xFFFFFFFF)。尝试从中加减,你会发现你可以回溯,让它是正确的

    但是,如果您要来回转换,我强烈建议您命名变量,以便清楚它们是什么类型,例如:

    int iValue, iResult;
    unsigned int uValue, uResult;
    
    如果在没有提示的情况下命名变量,很容易被更重要的问题分散注意力,忘记哪个变量是什么类型。您不希望强制转换为无符号,然后将其用作数组索引。

    指:

    • 加法操作将导致int转换为无符号int
    • 假设二者的补码表示和大小相同的类型,位模式不会改变
    • 从无符号整数到有符号整数的转换取决于实现。(但它的工作方式可能与目前大多数平台上的预期相同。)
    • 在组合大小不同的有符号和无符号时,规则稍微复杂一些

    从有符号到无符号的转换不一定只是复制或重新解释有符号值的表示形式。引用C标准(C99 6.3.1.3):

    当整数类型的值转换为除_Bool以外的其他整数类型时,如果 该值可以由新类型表示,但保持不变

    否则,如果新类型是无符号的,则通过重复添加或 比新类型中可以表示的最大值多减去一个 直到值在新类型的范围内

    否则,新类型已签名,且无法在其中表示值;要么 结果是定义了实现或发出了定义了实现的信号

    对于如今几乎普遍存在的两种补码表示法,ru
    int iValue, iResult;
    unsigned int uValue, uResult;
    
    unsigned int u = 1234;
    int i = -5678;
    
    unsigned int result = u + i;