已签名到未签名的转换

4

可能是重复问题:
一个谜语(用C语言)

看看这段代码

  #define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0])) 

  int array[] = {23,34,12,17,204,99,16}; 

  int main() 

  { 

      int d; 

      for(d=-1;d <= TOTAL_ELEMENTS-2;d++) 
          printf("%d\n",array[d+1]); 

      return 0;

  } 

现在这个循环将不会运行。 sizeof()会返回一个无符号值,所以TOTAL_ELEMENTS也是无符号的。 现在,谈到for循环,请告诉我一元运算符'-'是否适用于有符号整数2或者隐式转换成无符号后再使用'-'运算符。


我无法决定我是否喜欢这个问题,因为它指出了人们常常忽略的细节,或者是因为示例代码明显是糟糕的代码而让人讨厌。我希望这只是为了展示问题而编写的,并不存在于“现实生活”中。 - tvanfosson
这是一个相当人为的问题 - 更好的例子是检查有符号数是否低于最大值,然后将其传递给malloc。 - Mark
5个回答

8
在您的示例中,比较中的d被转换为一个unsigned int。但是,-1无法表示为一个unsigned int值,因此它被转换为UINT_MAX。为避免这种行为,您可以通过在比较的右侧添加(int)来将其转换为signed int
有关C语言中整数转换规则的详细信息,请参见了解整数转换规则

这是问题的前提。然而,我认为他在询问算术转换规则。 - Mark
我试图指出代码为什么不起作用,并提供了一个解释升级规则的文档链接。当然,为了给出完整的答案,我应该解释规则并解释说在从TOTAL_ELEMENTS中减去2之前,将其转换为无符号值。 - f3lix

2

在 d <= TOTAL_ELEMENTS-2 中没有一元运算符。

TOTAL_ELEMENTS-2 简化为一个二元运算符的表达式。因为其中一个操作数是无符号的,所以该表达式变成了无符号的。

对于 d <= TOTAL_ELEMENTS-2,d 的类型也会由于同样的原因转换为无符号整数。

相关标准的部分是第6.3.1.8#1节(ISO/IEC 9899:1999),其中写道:

"否则,如果具有无符号整数类型的操作数的等级大于或等于另一个操作数的类型的等级,则具有带符号整数类型的操作数将被转换为具有无符号整数类型的操作数的类型。"


2

是的,由于提升,d在这个表达式中也有无符号类型,这就是循环失败的原因。

然而,问题是C编译器是否会“认为”:

(unsigned) ((unsigned) 5 - (unsigned) 2)

即将2提升为无符号数,还是:

(unsigned) ((unsigned) 5 - (signed) 2)

即减法取两种类型的操作数。当然,这没有关系,因为对于两者来说,它们都是相同的操作。然而,整个重点在于减法将返回一个特定类型的值,因此理论上它只能采用该类型的参数。所以是第一种情况(无符号整数2)。

P.S. (-2)是一元的,而(5-2)是二元的。


0

看,那个“-”运算符是一件愚蠢的事情。忘了它吧。我意识到这是二元的“-”。

当2被转换为无符号整数时,它变成了无符号的2,所以TOTAL_ELEMENTS-2的值等于无符号的5,然后当d被转换为无符号整数时,它得到了一个很大的正值,所以循环失败了。

这里是不是发生了这种情况?

是的,我没有写这段代码,这是我在网上找到的一些C谜题。谢谢大家。


是的,这基本上就是发生的事情。 - f3lix

0

我怀疑 sizeof() 的无符号类型会传播到表达式 TOTAL_ELEMENTS-2,然后传播到 d <= TOTAL_ELEMENTS-2 的两个操作数。在 TOTAL_ELEMENTS 前面插入 (int) 可以解决这个问题。


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