【问题标题】:Loop starting at -1 doesn't print anything [duplicate]从-1开始的循环不打印任何内容[重复]
【发布时间】:2018-01-21 06:55:45
【问题描述】:

这个程序应该打印出array的元素,但是运行时没有输出。

#include <stdio.h>

#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;
}

为什么这个程序不显示任何输出?

【问题讨论】:

  • 带有硬编码变量名的宏自找麻烦。
  • 更改 d=0 确实会输出内容
  • @TonyTannous 但它没有解释 OP 中的问题是什么
  • @CIsForCookies 它是评论部分。我没有告诉他更改d=0 或提供解决方案。我只是想知道。
  • 您应该询问您的编译器。它通常会告诉您问题所在。在这种情况下也是如此。对于 gccclang 使用 -Wall -Wextra,对于 Visual C(++) 至少使用 /W3,最好至少在解决问题时使用 /W4

标签: c loops integer sizeof negative-number


【解决方案1】:

sizeof 返回一个无符号整数,所以TOTAL_ELEMENTS 也是无符号的。

d 已签名。最初,d-1。但是,在进行比较时,d 被隐式类型转换为无符号,因此与TOTAL_ELEMENTS 比较时,它不再是-1,它实际上是UINT_MAX(在我的机器上是4294967295,但可能其他人不同)。

还有,

如果您想解决此问题,请将TOTAL_ELEMENTS 类型转换为int

for(d = -1; d <= (int)(TOTAL_ELEMENTS - 2); d++) 

这将打印:

23
34
12
17
204
99
16

如您所料。您可能还想查看Comparison operation on unsigned and signed integers 以获取有关有符号-无符号比较主题的更多信息。

值得注意的是,打开编译器警告可以帮助您弄清楚发生了什么(正如 hyde 在他的 comment 中所观察到的):

$ gcc -Wall -Wextra test.c
test.c:7:17: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
      for(d = 0; d < TOTAL_ELEMENTS; d++) 
              ~ ^ ~~~~~~~~~~~~~~
1 warning generated.

或者,为什么不从0 开始d,然后运行到TOTAL_ELEMENTS - 1?您甚至可以放弃类型转换,这仅适用于 d = -1 的极端情况。

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

作为脚注,以下是相关的 C99 标准摘录:

  1. 6.3.1.8p2定义了有符号到无符号类型的转换。

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

  2. 6.3.1.3p2 定义了如何完成转换:通过将UINT_MAX + 1 添加到签名表示中。

    如果新类型是无符号的,则通过重复加减最大值的方式来转换值 可以用新类型表示,直到值在 新类型的范围。

    所以-1 => -1 + (UINT_MAX + 1) = UINT_MAX,对于这种情况。

【讨论】:

    【解决方案2】:

    我的 gcc 输出这个警告:

    warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
          for(d = 0; d < TOTAL_ELEMENTS; d++) 
    

    这意味着(TOTAL_ELEMENTS-2)unsigned intdsigned int。这使得表达式始终为 false 的初始值 d,因为 (unsigned int)(-1) &gt; (TOTAL_ELEMENTS-2)

    【讨论】:

    • 是的。教训:始终启用所有警告并阅读它们
    • 表达式不是总是假,对于d的初始值来说是假的。
    【解决方案3】:

    不同整数类型之间的二进制运算是在由所谓的常用算术转换定义的“通用”类型内执行的。所以 int d 是用值 -1 初始化的单数类型。当转换为 unsigned int 时,它将返回 unsigned int 的最大值,该最大值远大于返回的值 TOTAL_ELEMENTS 个。

    【讨论】:

    • unsigned int 你的答案应该是size_t。除此之外,你是正确的。
    猜你喜欢
    • 2020-10-01
    • 2016-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-15
    相关资源
    最近更新 更多