【问题标题】:Why is gcc not compiling this code consistently?为什么 gcc 不能一致地编译此代码?
【发布时间】:2016-02-01 15:43:31
【问题描述】:

我正在为我正在参加的 C 编程课程完成一项实验室作业。我在本地 Cygwin 目录中编写了代码,使用 gcc 编译它,生成的可执行文件完全按照我想要的方式运行,没有任何错误。

当我将我的代码复制到我学校的 UNIX 服务器并使用 gcc 编译它时,我没有收到任何错误,但是当我尝试运行它时,什么也没有发生。

我尝试做gcc 2darray.c -Wall -pedantic,这就是返回的内容:

2darray.c: In function 'main':
2darray.c:5:3: warning: missing braces around initializer [-Wmissing-braces]
2darray.c:5:3: warning: (near initialization for 'M[0]') [-Wmissing-braces]
2darray.c:5:24: warning: C++ style comments are not allowed in ISO C90 [enabled by default]
2darray.c:5:24: warning: (this will be reported only once per input file) [enabled by default]

这些错误提到了一些关于初始化数组M 的内容,但我认为初始化它的方式没有任何问题。这是我要编译的代码:

#include <stdio.h>

int main(void)
{
  int M[10][10] = {0}; // creating a 10x10 array and initializing it to 0
  int i, j; // loop variables
  int sum[10] = {0}; // creating an array to hold the sums of each column of 2d array M

  for (i = 1; i < 10; i++) // assigning values to array M as specified in directions
    {
      for (j = i - 1; j < i; j++)
        {
          M[i][j] = -i;
          M[i][j+1] = i;
          M[i][j+2] = -i;
        }
    }

  for (i = 0; i < 10; i++) // printing array M
    {
      for(j = 0; j < 10; j++)
        {
          printf("%3d", M[i][j]);
        }
      printf("\n");
    }

  printf("\n");
  for (i = 0; i < 10; i++) // calculating sum of each column
    {
      for (j = 0; j < 10; j++)
        {
          sum[i] = M[j][i] + sum[i];
        }
      printf("%3d", sum[i]);  // printing array sum
    }

  return 0;
}

我尝试在变量声明和第一个 for 循环之间插入 printf 语句并打印语句,所以我的循环中可能出现问题?

如果相关,以下是我的 Cygwin 目录中的输出以及我学校的 UNIX 目录中的输出:

  0  0  0  0  0  0  0  0  0  0
 -1  1 -1  0  0  0  0  0  0  0
  0 -2  2 -2  0  0  0  0  0  0
  0  0 -3  3 -3  0  0  0  0  0
  0  0  0 -4  4 -4  0  0  0  0
  0  0  0  0 -5  5 -5  0  0  0
  0  0  0  0  0 -6  6 -6  0  0
  0  0  0  0  0  0 -7  7 -7  0
  0  0  0  0  0  0  0 -8  8 -8
  0  0  0  0  0  0  0  0 -9  9

 -1 -1 -2 -3 -4 -5 -6 -7 -8  1

【问题讨论】:

  • 尝试将int M[10][10] = {0};更改为int M[10][10] = {{0}};
  • 我只是尝试修复警告。我仍在尝试了解您的问题。您可以更好地解释“可执行文件不起作用”的含义。
  • 并使用选项-std=c99
  • “不起作用”不是问题描述。
  • M[i][j+2] = -i; : 当i : 9 时,越界。

标签: c gcc multidimensional-array


【解决方案1】:

您正在访问数组M 超出其边界的一行,导致未定义的行为。

for (i = 1; i < 10; i++) 
// i ranges from 1 to 9
  {
    for (j = i - 1; j < i; j++)
    // j ranges from i-1 (0 when i==1) to i-1 (8 when i==9)
    // Consider what happens when j==8
      {
        M[i][j] = -i;       // j == 8
        M[i][j+1] = i;      // j == 9
        M[i][j+2] = -i;     // j == 10, out of bounds
      }
  }

当我查看您的代码时,j+2 索引让我觉得最有可能进行越界访问。我复制了你的程序并添加了一行:

      M[i][j] = -i;
      M[i][j+1] = i;
      if (j+2 >= 10) puts("OUT OF RANGE");
      M[i][j+2] = -i;

当我运行程序时,它打印出OUT OF RANGE

至于您从gcc -Wall -pedantic 收到的警告,它们并不是真正的问题。使用-std=c99 编译可以避免有关// cmets 的警告。 “缺少大括号”警告是虚假的。嵌套数据结构的初始化程序中的嵌套大括号是可选的,{0} 是用于将整个数据结构(数组、结构、联合)初始化为零的完全有效的习惯用法。最新版本的 gcc(尤其是 5.2.0)不会对此发出警告。

【讨论】:

  • 很好,但问题是提前了一步。 M的第二个索引可以高达9,所以当j为9时,j+1的行就有问题了。
  • 我认为不是真的。 9在范围内,不是吗?
  • @donjuedo j &lt; ii &lt; 10,所以 j 的最大值是 8。
  • 感谢您的帮助,基思。我在第一个嵌套的for 循环中的第三个表达式之前添加了一个if (j+2 &gt; 9) break; 语句,它起作用了。
  • @user10721:添加break 可以避免未定义的行为;我不知道这是否是最好的解决方案。这取决于程序应该做什么,而你没有给我们要求。
【解决方案2】:

clang 和 gcc 的最新版本附带了一个可以解决此类问题的工具。请始终使用它,它将为您节省大量查找错误的时间。

$ gcc s.c -Wall -Wextra -fsanitize=undefined
$ ./a.out
s.c:15:15: runtime error: index 10 out of bounds for type 'int [10]'
s.c:15:21: runtime error: store to address 0x7fff6c53f2c0 with insufficient space for an object of type 'int'
0x7fff6c53f2c0: note: pointer points here
 09 00 00 00  e5 ef 74 8a 11 7f 00 00  08 00 00 00 09 00 00 00  b0 10 40 00 00 00 00 00  00 00 00 00
              ^

显然,cygwin 可能还不支持 libubsan,因此您可能需要-fsanitize-undefined-trap-on-error,它用一个简单的陷阱替换了不错的错误消息,然后您可以使用 gdb 进行调查。是的,调试器是另一种工具,需要一些时间来学习,但不会太多,它可以节省您更多时间寻找错误。

【讨论】:

    猜你喜欢
    • 2013-08-08
    • 1970-01-01
    • 1970-01-01
    • 2015-09-15
    • 2017-11-09
    • 2012-07-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多