3

次の構成の3つの異なるマシンがあります。

  1. OpenSuSe 12.1、Linuxカーネル3.1.10、gcc 4.6.2
  2. Debian 6、Linuxカーネル2.6.32、gcc 4.4.5
  3. CentOS 5.6、Linuxカーネル2.6.18、gcc 4.1.2

それらのアーキテクチャはすべてx86_64です。CentOSのソフトウェアバージョンはDebianのバージョンよりも古いが、OpenSuSeソフトウェアのバージョンはDebianのバージョンよりも新しいことに注意してください。

そして、私は次のサンプルコードを持っています:

#include <cstdio>
#include <cstdlib>

unsigned int cols=5;
unsigned int rows=6;

int main()
{
        //allocating...
        double **mat=new double*[rows];
        double *col=new double[rows];
        for(unsigned int i=0;i<rows;++i)
        {
                mat[i]=new double[cols];
        }

        //filling with something...
        for(unsigned int i=0;i<rows;++i)
        {
                for(unsigned int j=0;j<cols;++j)
                {
                        mat[i][j]=i+j;
                }
        }

        //testing...
        unsigned long long sum,add;
        for(unsigned int i=0;i<cols;++i)
        {
                sum=0;
                for(unsigned int j=0;j<rows;++j)
                {
                        col[j]=mat[j][i];
                        add=*((unsigned long long*) (&(col[j])));
                        sum+=add;
                }

                printf("%llu\n",sum);
        }

        return 0;
}

オプションなしでこのコードをコンパイルした場合:

g++ code.cpp

すべてのマシンで同じように実行されます。

しかし、でコンパイルすると-O2、1番目と3番目のマシンで同じように動作しますが、2番目のマシン(Debian)では-O2最適化によって壊れます。

これは、次の1台目のマシンでのこのコードの出力です-O2

4619567317775286272
9238008735643729920
9250393634618998784
9259400833873739776
9266719183268216832

そしてこれは2番目のマシンにあり-O2ます:

0
4619567317775286272
9238008735643729920
9250393634618998784
9259400833873739776

2番目のマシンの出力は1番目の出力のように見え、1行下にシフトされます。

に置き換える(&(col[j]))(&(mat[j][i]))、コードは正常に機能し始めます。

オプションを使用した2番目のマシンでのコンパイラの出力は次のとおり-vです。-O2

Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.4.5-8' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.4 --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.4.5 (Debian 4.4.5-8) 
COLLECT_GCC_OPTIONS='-v' '-O2' '-shared-libgcc' '-mtune=generic'
 /usr/lib/gcc/x86_64-linux-gnu/4.4.5/cc1plus -quiet -v -D_GNU_SOURCE dmtest.cpp -quiet -dumpbase dmtest.cpp -mtune=generic -auxbase dmtest -O2 -version -o /tmp/cc6v7CNY.s
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../x86_64-linux-gnu/include"
ignoring nonexistent directory "/usr/include/x86_64-linux-gnu"
#include "..." search starts here:
#include <...> search starts here:
 /usr/include/c++/4.4
 /usr/include/c++/4.4/x86_64-linux-gnu
 /usr/include/c++/4.4/backward
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/4.4.5/include
 /usr/lib/gcc/x86_64-linux-gnu/4.4.5/include-fixed
 /usr/include
End of search list.
GNU C++ (Debian 4.4.5-8) version 4.4.5 (x86_64-linux-gnu)
        compiled by GNU C version 4.4.5, GMP version 4.3.2, MPFR version 3.0.0-p3.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 5a2e15051eaa06a84cf6320b754ba993
COLLECT_GCC_OPTIONS='-v' '-O2' '-shared-libgcc' '-mtune=generic'
 as -V -Qy -o /tmp/ccL37GHG.o /tmp/cc6v7CNY.s
GNU assembler version 2.20.1 (x86_64-linux-gnu) using BFD version (GNU Binutils for Debian) 2.20.1-system.20100303
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-O2' '-shared-libgcc' '-mtune=generic'
 /usr/lib/gcc/x86_64-linux-gnu/4.4.5/collect2 --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=both -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../.. /tmp/ccL37GHG.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/4.4.5/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.4.5/../../../../lib/crtn.o

そのような行動の理由は何ですか?私のコードは正しくありませんか、それともgcc 4.4.5のバグですか?

4

2 に答える 2

4

これは型のパンニングであるため、未定義の動作です。あなたがそれについての警告を受けていないことに私は驚いています。

もちろん、通常は期待どおりに機能しますが、それでも未定義の動作です。

未定義動作の部分を回避するには、にキャストしてchar *各バイトを連続して読み取ることができます。これはあなたが見ている振る舞いを修正しますか?

于 2012-11-19T18:39:21.033 に答える
2

このブログ エントリによると、GCC 4.4 では厳密なエイリアシング ルールが適用され-O2ます。したがって、型パニング アクセスは、未定義の動作をもたらします。残念ながら、厳密なエイリアシング ルールに違反しているという警告を受け取るには、 でコンパイルする必要があります-Wstrict-aliasing

おそらく、GCC の新しいバージョンは古い動作に戻り、厳密なエイリアシングを有効にするかどうかの決定をユーザーに委ねています。

于 2012-11-20T09:05:16.930 に答える