And*_*ren 2 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);
}
Run Code Online (Sandbox Code Playgroud)
启用优化(/ O2)后,不会执行第一个指针递减的第一行.我正在调试优化和非优化的构建并且优化的构建步骤超过减量,而非优化的程序执行它.当以后使用arr [*index]访问数组时,这会产生可观察到的行为差异.
UPDATE
正如@stefaanv所指出的那样,如果编译器改为减少访问索引,那么编译器确实可以省略该减量,而这似乎是这样做的.因此,省略的减量不是导致行为差异的原因.相反,使用矩阵导致它的某些东西.
进一步展望我已将其缩小为包含执行矩阵乘法的嵌套循环的方法.该方法的一部分如下所示:涉及3个数组:a,wa和t.在该方法的开头,f2c转换器使用递减,以便fortran中6乘6的数组是double[36]c中的平坦.但是为了能够使用旧的索引,它将数组指针移回矩阵中的列数.
通常在这个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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以问题是:
这是否意味着行为未定义,并且当您执行f2c在此处执行的操作时可能会在优化下中断,即从double [36]数组指针中减去7,然后在正确的位置(偏移7)访问数组中的所有项目?
编辑:在C FAQ中找到了这个,这适用于此吗?
只要指针指向同一个分配的存储器块内,或者指向一个超过它的虚构"终止"元素,就只定义指针算术; 否则,即使指针未被解除引用,行为也是未定义的 .....参考文献:K&R2 Sec.5.3 p.100,Sec.5.4 pp.102-3,Sec.A7.7 pp.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);
Run Code Online (Sandbox Code Playgroud)
然后,无论优化如何,该方法都会产生相同的(预期的)输出.仅减1的单维数组似乎不会产生任何问题.
我可以使用上面的访问方法更改程序中的所有多维数组,但是单个dim数组太多而无法手动更改,所以理想情况下我想要一个适用于两者的解决方案.
新问题:
优化器应该只确保没有可观察的行为更改,因此它可以选择不执行减量并使用递减的索引访问数据(额外的偏移量可以是操作码的一部分),因为该函数使用了副本指向数组的指针.您没有告诉我们实际访问数组的方式以及优化器是否实际引入了错误,因此我只能猜测这一点.
但是正如slartibartfast已经说过的那样:它是未定义的行为,int val = arr1[*index-1];在检查*index> 0之后应该替换减量