c++ - 由 C++ 编译器优化时,F2C 翻译的代码会中断

标签 c++ c visual-c++ f2c

我有一个 C++ 程序,其方法看起来像这样:

int myMethod(int* arr1, int* arr2, int* index)
{
    arr1--;        
    arr2--;
    int val = arr1[*index];
    int val2 = arr2[val];
    return doMoreThings(val);
}

在启用优化 (/O2) 的情况下,不会执行第一个指针递减的第一行。我正在并排调试优化的和非优化的构建,优化的构建步进递减,而非优化的程序执行它。当它稍后使用 arr[*index] 访问数组时,这会产生可观察到的行为差异。

更新

正如@stefaanv 指出的那样,编译器确实可能会忽略递减,如果它改为更改为递减的访问索引,而这似乎是这样做的。因此,省略的减量并不是导致行为差异的原因。相反,在使用矩阵时有一些原因导致了它。

进一步看,我已将其缩小为包含执行矩阵乘法的嵌套循环的方法。该方法的一部分如下所示:涉及 3 个数组:a、wa 和 t。在该方法的开头,f2c 翻译器使用了递减,因此在 fortran 中为 6 x 6 的数组在 c 中是一个平面 double[36]。但是为了能够使用旧的索引,它将数组指针向后移动矩阵中的列数。

通常在这个 f2c 翻译程序中,平面数组作为 &someArray[1] 传递,方法开始时将每个数组递减 1。 @Christoph 指出这应该是有效的,因为数组的递减永远不会超出其声明的范围。

在这种方法的情况下,传入的数组不会作为指向元素的指针进一步传递到数组 &someArray[1] 但这里的数组是声明为固定大小的局部静态数组例如mat[36] 并直接传递给乘法方法。

void test()
{
    double mat[36];
    ...
    mul(mat, .., ..)
}

void mul(double* a, double* t, double*wa, int M, int N, int K)
{
    // F2C array decrements.
    a -= (1+M); // E.g. decrement by seven for a[6x6]!
    t -= (1+N); 
    wa--;
    ...
    for (j = K; j <= M; ++j) {         
       for (i = 1; i <= N; ++i) {
          ii = K;
          wa[i] = 0.;          
          for (p = 1; p <= N; ++p) {
             wa[i] += t[p + i * t_dim1] * a[ii + j * a_dim1];
             ++ii;
          }
       }

       ii = K;      
       for (i = 1; i <= N; ++i) {
          a[ii + j * a_dim1] = wa[i];
          if (j > kn) {
             a[j + ii * a_dim1] = wa[i];
          }
          ++ii;
      }
    }
 }    

那么问题是:

这是否意味着当您执行 f2c 在此处执行的操作时,行为未定义并且可能会在优化下中断,即从 double[36] 数组指针中减去 7,然后在正确的位置访问数组中的所有项(偏移量 7)?

编辑:在 C FAQ 中找到这个, 这在这里适用吗?

Pointer arithmetic is defined only as long as the pointer points within the same allocated block of memory, or to the imaginary "terminating" element one past it; otherwise, the behavior is undefined, even if the pointer is not dereferenced. .... References: K&R2 Sec. 5.3 p. 100, Sec. 5.4 pp. 102-3, Sec. A7.7 pp. 205-6; ISO Sec. 6.3.6; Rationale Sec. 3.2.2.3.

更新 2:

如果我使用递减索引而不是递减指针重新编译多维数组,

#define a_ref(a_1,a_2) a[(a_2)*a_dim1 + a_1 - 1 - a_dim1]

a_ref(1,2);

然后,无论优化如何,该方法都会产生相同的(预期的)输出。仅递减 1 的一维数组似乎不会产生任何问题。

我可以将程序中的所有多维数组更改为使用上述访问方法,但单个 dim 数组太多而无法手动更改,因此理想情况下我想要一个适用于两者的解决方案。

新问题:

  • f2c 是否可以选择使用此数组访问方法而不是指针操作?这似乎是对 f2c 的简单更改,并生成定义明确的代码,因此您会认为它已经是一个选项。
  • 这个问题是否有任何其他解决方案(除了跳过优化并希望程序表现良好,尽管依赖于未定义的行为)。
  • 我可以在 C++ 编译器中做些什么吗?我使用 Microsoft C++ (2010) 作为托管 C++ 项目进行编译。

最佳答案

优化器只应确保没有可观察到的行为变化,因此它可以选择不进行递减并使用递减索引访问数据(额外的偏移量可以是操作码的一部分),因为函数使用指向数组的指针的拷贝。你没有告诉我们数组实际上是如何访问的,优化器是否真的引入了错误,所以我只能猜测。

但正如 slartibartfast 已经说过的:这是未定义的行为,在检查 *index > 0

后,减量应替换为 int val = arr1[*index-1];

关于c++ - 由 C++ 编译器优化时,F2C 翻译的代码会中断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10895769/

相关文章:

c - 使用 C 的另一个结构内的灵活长度结构数组

c++ - 编译器是否允许进行这样的优化?

c++ - 创建多个txt文件以在c++中存储数据

c++ - 如何使用 strncpy_s() 函数实现 strncpy() 功能?

c++ - 使用正则表达式解析命令

c++ - 超出 DirectX11 视频内存

通过 LED 循环

c++ - 在 unique_ptr vector 中搜索时出现非标准扩展警告

c - 'printf' 在 C 中带有前导零

C++ - 用 %20 替换空格