我有一个 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 的数组double[36]
在 c 中是一个平面。但是为了能够使用旧的索引,它将数组指针向后移动矩阵中的列数。
通常在这个 f2c 翻译的程序中,平面数组是传递的&someArray[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中找到了这个,这适用于这里吗?
只要指针指向同一个分配的内存块内,或者指向一个假想的“终止”元素,就可以定义指针算术;否则,行为未定义, 即使指针未取消引用。.... 参考文献:K&R2 Sec。5.3 页。100,秒。5.4 第 102-3 页,秒。A7.7 第 205-6 页;ISO 秒。6.3.6;理由二。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);
然后,无论优化如何,该方法都会产生相同的(预期的)输出。仅减一的一维数组似乎不会产生任何问题。
我可以将程序中的所有多维数组更改为使用上述访问方法,但是单个暗淡数组太多而无法手动更改,因此理想情况下我想要一个对两者都适用的解决方案。
新问题:
- f2c 是否可以选择使用此数组访问方法而不是指针摆弄?似乎这将是 f2c 中的一个简单更改,并生成定义良好的代码,因此您会认为它已经是一个选项。
- 这个问题是否有其他解决方案(除了跳过优化并希望程序表现良好,尽管依赖于未定义的行为)。
- 我可以在 c++ 编译器中做些什么吗?我使用 Microsoft C++ (2010) 作为托管 c++ 项目进行编译。