无符号数转有符号数是否未定义?

12
void fun(){
    signed int a=-5;
    unsigned int b=-5;
    printf("the value of b is %u\n",b);
    if(a==b)
         printf("same\n");
    else
         printf("diff");
}

它打印出:

4294967291

同样的值

在第二行中,有符号值被转换为无符号值。因此,b的值为UINTMAX + 1-5 = 4294967291。

我的问题是比较运算中发生了什么。

1)a是否再次转换为无符号值并与b进行比较?

2)b(即无符号值)是否会自动转换为有符号值并进行比较?

3)由于int溢出,从无符号值到有符号值的转换是否未定义?

我已经阅读了其他关于这个主题的帖子。我只想澄清问题2和3。


部分答案在这里:https://dev59.com/fEvSa4cB1Zd3GeqPivlL#2262746 - triclosan
这个链接解决了我的问题2。 - hackrock
请注意,这些问题彼此无关。这里有两个问题:当信号和无符号类型在同一操作中混合时会发生什么,以及当您尝试将有符号整数存储在无符号整数中时会发生什么。 - Lundin
3个回答

21

1) 是否将a再次转换为无符号数,并与b进行比较?

是的。在表达式(a==b)中,隐式类型转换被称为“平衡”(正式名称为“通常算术转换”)。平衡规则指定,如果比较的是大小和类型相同的有符号和无符号操作数,则有符号操作数将转换为无符号。

2) b(即无符号数)是否会自动转换为有符号值并进行比较?

不会,在您的示例中它永远不会转换为有符号数。

3) 由于整型溢出,从无符号数到有符号数的转换是否未定义?

这是标准规定:(C11)

6.3.1.3 有符号和无符号整数

1 当将具有整数类型的值转换为除_Bool之外的另一种整数类型时, 如果该值可以用新类型表示,则该值不变。

2 否则,如果新类型是无符号的,则通过重复添加或减去一个超过新类型中可表示的最大值的值,直到该值位于新类型的范围内来转换该值。

3 否则,新类型是有符号的,且该值无法表示在其中;结果要么是实现定义的,要么会引发实现定义的信号。

换句话说,如果编译器能够在上面的2)中进行转换,则行为是良好定义的。如果不能,则结果取决于编译器实现。

这不是未定义的行为。


1
@rocky 为避免可能的误解:在第2点中,Lundin指的是“在你的例子中”, unsigned int 永远不会自动转换为 int 进行转换。如果将一个4字节的 unsigned int 与一个8字节的 long long int 进行比较,则无符号值会自动转换为较大的有符号类型。 - Daniel Fischer
@DanielFischer 但是问题中没有long long int... 无论如何,最好的做法是阅读有关通常算术转换及其子规则所称的整数提升规则。这对于任何C程序员来说都是必备知识。 - Lundin
是的,但是“b是否会自动转换为有符号值...”可能涉及到更一般的情况,所以我认为明确“在你的例子中”的含义可能是有益的,以防万一。 - Daniel Fischer
这个表述可以更好一些...无疑,无符号短整型和字符可以转换为有符号类型,但它们永远不会被转换为负值 - Antti Haapala -- Слава Україні
@AnttiHaapala 我不明白这些与这篇非常古老的帖子有什么关系。自从这篇文章发布以来,已经有更好的帖子了:隐式类型提升规则 - Lundin
显示剩余2条评论

2

答案:

  1. a 被转换为 unsigned int
  2. 如果 a 的范围比 b 的有符号对应类型更宽(我可以想象 long long a 可以做到),b 将被转换为有符号类型。
  3. 如果无法正确表示无符号值在转换为有符号类型后,您将会得到实现定义的行为。如果可以,则没有问题。

4
仅仅是为了更加严谨,在第三点中,它不是未定义行为,“结果要么是实现定义的,要么会引发实现定义的信号”,而是实现定义的。 - Daniel Fischer
我已将上面的评论标记为“不再需要”,因为与此同时,有人编辑了答案以解决评论中提到的问题。因此,据我所知,该评论现在是多余/过时的。 - Andreas Wenzel

-3
b = -5;

这被视为溢出并且是未定义的行为。将signedunsigned进行比较会自动将操作数提升为unsigned。-在溢出的情况下,您将再次发现自己处于未定义行为的情况下。- 完全错误,请参见 [编辑] 以下

另请参见http://c-faq.com/expr/preservingrules.html

[编辑]更正-标准确实规定在从负有符号转换为无符号时应使用2补码。


5
不,b = -5;已经被定义了。标准明确规定,从有符号整数到无符号整数的转换不会发生溢出,并且会给你一个对 UTYPE_MAX + 1 取模后的值。 - Daniel Fischer
@DanielFischer:它们会“溢出”,但不会导致未定义行为。 - Alexey Frunze
3
据我了解,在标准术语中,溢出并不指无符号整数的明确定义的包装,参见3.4.3中“未定义行为的一个例子是整数溢出的行为”。当然,在日常语言中,这也被称为溢出。 - Daniel Fischer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接