类型转换 - 无符号到符号int /炭类型转换 - 无符号到符号int /炭(Type conver

2019-05-08 17:06发布

我试着执行以下程序:

#include <stdio.h>

int main() {
    signed char a = -5;
    unsigned char b = -5;
    int c = -5;
    unsigned int d = -5;

    if (a == b)
        printf("\r\n char is SAME!!!");
    else
        printf("\r\n char is DIFF!!!");

    if (c == d)
        printf("\r\n int is SAME!!!");
    else
        printf("\r\n int is DIFF!!!");

    return 0;
}

对于这个计划,我得到的输出:

char是DIFF! int是SAME!

为什么我们得到两个不同的输出?
如果输出是如下?

焦炭一样! int是SAME!

一个键盘连接 。

Answer 1:

这是因为,在C的各个隐式类型转换规则有其中两个,一个C程序员必须知道: 通常的算术转换整数促销 (后者是前者的一部分)。

在炭情况下,你有类型(signed char) == (unsigned char) 。 这些都是小的整数类型 。 其他如小整数类型是boolshort整数提升规则指出,当一个小的整数类型是操作的操作数,它的类型将得到提升,以int ,这是签署。 如果类型为带符号会发生这种情况没有关系。

在的情况下signed char ,该标志将被保留,这将提升为int包含值-5。 在的情况下unsigned char ,它包含一个值,该值是251(0xFB的才能)。 这将提升为int包含相同的值。 你结束了

if( (int)-5 == (int)251 )

在整数的情况下,你有类型(signed int) == (unsigned int) 。 他们是不小的整数类型,所以整促销活动不适用。 取而代之的是,它们由通常的算术转换 ,这指出,如果两个操作数具有相同的“等级”(尺寸),但不同的符号类型,已签名的操作数转换为相同的类型无符号的一个平衡。 你结束了

if( (unsigned int)-5 == (unsigned int)-5)


Answer 2:

酷的问题!

int比较有效,因为这两个整数包含完全相同的位,所以他们基本上是相同的。 但关于什么char S'

嗯,C含蓄地促进char s到int S于各种场合。 这是其中之一。 您的代码表示, if(a==b)但什么编译结果实际上是对是:

if((int)a==(int)b) 

(int)a为-5,但(int)b是251.这些是绝对不一样的。

编辑:由于@碳酸酸指出, (int)b是251仅当一个char是8位长。 如果int是32位长, (int)b是-32764。

REDIT:有意见讨论答案的性质,如果一个字节是不是8位长的一大堆。 在这种情况下,唯一的区别是(int)b不是251但具有不同的数,这是不-5。 这并不是这仍然是非常酷的真正的问题有关。



Answer 3:

欢迎到整型提升 。 如果我可以从网站引用:

如果int可以表示原始类型的所有值,该值被转换为int; 否则,它被转换为一个unsigned int。 这些被称为整数促销。 所有其它类型在整数提升不会改变。

C可让人有些困惑,当你做比较,如这些,我最近有些摸不着头脑与下面的挑逗我的非C编程的朋友:

#include <stdio.h>
#include <string.h>

int main()
{
    char* string = "One looooooooooong string";

    printf("%d\n", strlen(string));

    if (strlen(string) < -1) printf("This cannot be happening :(");

    return 0;
}

这的确不打印This cannot be happening :(而且似乎表明,25是小于-1!

然而什么情况下是-1表示为无符号整数,由于底层的比特表示等于4294967295 32位系统。 自然25比4294967295较小。

如果我们不过显式转换size_t通过返回类型strlen作为一个有符号整数:

if ((int)(strlen(string)) < -1)

然后,它会比较对25 -1和所有将与世界很好。

一个好的编译器应该提醒你注意一个无符号和符号整数之间的比较,但它依然是那么容易错过(特别是如果你不启用警告)。

这是因为所有的基本类型有签名的Java程序员特别混乱。 以下是詹姆斯·高斯林(Java的创始人之一) 不得不话要说 :

高斯林:我作为一个语言设计者,我真的不认为我自己这些天,有什么“简单”真的结束了的意思是我能想到J.随机开发持有该规范在他的头上。 这个定义说,例如,Java是没有 - 事实上很多这些语言结了大量的边界情况,事情没有人真正理解。 测验任何C开发者关于无符号,很快你会发现,几乎没有C语言开发人员真正了解发生的事情与签名,未签名什么是算术。 这样的事情使C复合物。 的Java语言的部分是,我认为,很简单。 该库必须抬起头来。



Answer 4:

的十六进制表示-5是:

  • 8位二进制补码signed char0xfb
  • 32位二进制补码signed int0xfffffffb

当您将符号数转换为一个无符号数,或反之,则编译器......恰恰没有。 有什么呢? 数量或者是转换或没有,在这种情况下,不确定的或实现定义如下(我没有去查看它)和最有效的实现定义的行为是什么也不做。

所以,的十六进制表示法(unsigned <type>)-5是:

  • 8位, unsigned char0xfb
  • 32位, unsigned int0xfffffffb

看起来熟悉? 他们是位对位相同签名的版本。

当你写if (a == b)其中ab是类型的char ,读什么书,编译器实际上需要的是if ((int)a == (int)b) (这是一个“整型提升”其他人都被敲打一下。)

所以,当我们转换会发生什么charint

  • 8位signed char到32位signed int0xfb - > 0xfffffffb
    • 嗯,这是有道理的,因为它的表示相匹配-5以上!
    • 它被称为“符号扩展”,因为它复制字节的“签位”,向左进入新的,更广泛的价值的最高位。
  • 8位unsigned char为32位signed int0xfb - > 0x000000fb
    • 这一次,它做了“零扩展”,因为源类型是无符号的 ,所以没有符号位复制。

所以, a == b确实0xfffffffb == 0x000000fb =>不匹配!

而且, c == d确实0xfffffffb == 0xfffffffb =>比赛!



Answer 5:

我的观点是:没有你在编译时警告“比较有符号和无符号表情”?

编译器试图告诉你,他有权做疯狂的事情! :)我想补充的,疯狂的事情会发生使用大值,接近原始类型的能力。 和

 unsigned int d = -5;

绝对分配大值d,这相当于(即使,可能不保证当量)为:

 unsigned int d = UINT_MAX -4; ///Since -1 is UINT_MAX

编辑:

然而,有趣的是,发现只有第二比较给出一个警告(查看代码) 。 因此,这意味着应用转换规则编译器确信不会有在之间的比较误差unsigned charchar (比较过程中它们将被转换为一个类型,可以安全地表示它的所有可能的值)。 他是对的这一点。 然后,它通知你,这将不会是的情况下unsigned intint :所述比较所述2的一个将被转换为一个类型,不能完全代表它期间。

为了完整起见, 我检查它也简称 :编译器以同样的方式比字符的行为,并如市场预期,也有在运行时没有错误。

与此相关的话题,最近,我问这个问题 (然而,C ++面向)。



文章来源: Type conversion - unsigned to signed int/char