将128分配给c

时间:2018-06-26 16:49:42

标签: c char signed

输出结果是128的32位2的补码,即4294967168。如何?

#include <stdio.h>
int main()
{
    char a;
    a=128;
    if(a==-128)
    {
        printf("%u\n",a);
    }
    return 0;
}

3 个答案:

答案 0 :(得分:5)

在打开警告的情况下编译代码会给出:

warning: overflow in conversion from 'int' to 'char' changes value from '128' to '-128' [-Woverflow]

告诉您作业a=128;在平台上的定义不正确。

标准说:

  

6.3.1.3有符号和无符号整数

     

1将整数类型的值转换为_Bool以外的其他整数类型时,如果该值可以用新类型表示,则该值不变。

     

2否则,如果新类型是无符号的,则通过重复添加或减去新类型所能表示的最大值,直到该值在新类型的范围内,来转换该值。

     

3否则,将对新类型进行签名,并且无法在其中表示值; 结果是实现定义的,还是引发了实现定义的信号

所以我们不知道发生了什么,因为这取决于您的系统。

但是,如果我们做一些猜测(请注意这只是一个猜测):

128作为8位将是0b1000.0000

因此,当您致电printf并转换为int时,将出现一个符号扩展名,如:

 0b1000.0000 ==> 0b1111.1111.1111.1111.1111.1111.1000.0000

以无符号形式打印的代表数字4294967168

答案 1 :(得分:1)

让您到达那里的步骤顺序如下:

  1. 您将128分配给char
  2. 在您的实现中,charsigned char,最大值为127,因此有128个溢出。
  3. 您的实现将128解释为0x80。它使用二进制补码,所以(int8_t)0x80代表(int8_t)-128
  4. 出于历史原因(与最初开发C的DEC PDP微型计算机的指令集有关),C在许多情况下(包括算术表达式)都会推广短于intint的有符号类型,像==这样的比较和函数printf()的可变参数,它们不绑定到原型,而是仍然使用K&R C的旧参数提升规则。
  5. 在您的实现中,int的宽度为32位,并且也是2的补码,因此(int32_t)-128的符号扩展为0xFFFFFF80
  6. 当您进行类似printf("%u", x)的调用时,运行时会将int参数解释为unsigned int
  7. 0xFFFFFF80是一个无符号的32位整数,表示4,294,967,168。
  8. "%u\n"格式说明符将其打印出来,且不带逗号(或其他分隔符),后跟换行符。

这都是合法的,但其他许多可能的结果也是如此。该代码有错误,不能移植。

确保您不会超出类型范围! (或者,如果不可避免,则将无符号标量的溢出定义为模块化算术,因此应具有更好的表现。)此处的解决方法是使用unsigned char,其范围为0到(至少)255,而不是char

答案 2 :(得分:0)

首先,正如我希望您理解的那样,您发布的代码中充满了错误,并且您不希望依赖于其输出。如果您试图在真实程序中执行这些操作中的任何一种,则可能希望以其他更明确,更可移植的方式执行。

所以我认为您只是出于好奇而问,我本着同样的精神回答。

计算机上的类型char可能是带符号的8位数字。因此其范围是从-128到+127。所以+128不适合。

当您尝试将值+128塞入带符号的8位数字时,您可能最终会得到值-128。基于您的if语句显然成功的事实,这似乎就是您正在发生的事情。

因此,接下来我们尝试获取-128值并将其打印为好像是unsigned int,它在您的计算机上显然是32位类型。它可以容纳0到4294967295范围内的数字,显然不包括-128。但是,无符号整数通常会很好地对它们的范围取模,因此,如果将4294967296加到-128,我们将得到4294967168,这正是您看到的数字。

现在我们已经解决了这个问题,我们以后再决定不要阻塞char变量中不适合的数字,也不要使用%u格式说明符打印带符号的数量。