4

次のテストプログラムがあります。

#include <string.h>
int q(int *p) {
    int x;
    memcpy(&x,p,sizeof(int));
    x+=12;
    memcpy(p,&x,sizeof(int));
    return p[0];
}

arm-linux-gnueabihf 用に GCC 4.7.2 を使用してこれをコンパイルすると、コンパイラはポインター アクセスがアラインされていない可能性があると推測し、アセンブリ出力のロードとストアに注釈を付けます。次に例を示します。

    ldr     r0, [r0, #0]    @ unaligned

でコンパイルすると-mno-unaligned-access、コンパイラは直接のロードとストアをまったく発行せず、memcpy代わりにライブラリを呼び出します。しかし、実際には、この場合のポインタは整列されていないはずです。これはgccの見落としですか、それとも間違っていますか?

4

4 に答える 4

2

への呼び出しでa にキャストされていることgccに確かに混乱していると思いますが、そのようなポインターの最悪の事態を想定しています。基になるポインターが適切に配置されているかどうかを確認しようとした可能性があります。より高い最適化レベルを試しましたか? レベルが高いほど賢くなるのかもしれません。int*void*memcpygcc

gccまた、すべてのコードでポインターのアライメントが保証されない可能性もありintますが、それは賢明ではなく、ありそうもないことです。

int*pコンパイラは、節 6.2.3.2 ad 7 により、正しいアラインメントを想定することが許可されています。

オブジェクト型へのポインターは、別のオブジェクト型へのポインターに変換される場合があります。結果のポインタが参照される型に対して正しくアラインされていない 68) 場合、動作は未定義です。

注 68) は、正しく配置されていることの推移性に関するものです。

于 2013-04-24T12:17:42.537 に答える
2

値のロードとストアよりも C コンパイラで最適化されているものはほとんどありませんint。これは設計上、マシンにとって自然なサイズです。

関数を次のように記述します。

int q(int *p) {
    return *p += 12;
}

これにより、オプティマイザーがインライン化して単純なロードとストアに縮小することを期待しているライブラリ ルーチンへの 2 回の呼び出しが回避され、整数値パラメーターをその場で変更して結果を返すという意図が表現されます。

を使用memcpyして整数を割り当てると、意図がわかりにくくなります。

この質問が、より大きな問題を混乱の最小サイズの例に縮小した結果である場合、私の実装は直接役に立たない可能性があります。しかし、 の型psome_complex_struct *ではなく であってもint *、アドバイスは適用されます。代入演算子が機能します。memcpy意味のある場所よりも優先して使用してください。

于 2013-04-24T17:53:39.510 に答える
1

これが私が思いついた解決策で、データ フィールドへのアクセスにいくつかの代替手段を実装しています。

// #define USE_MEMCPY
// #define USE_PACKED
#ifdef __cplusplus
template <typename T> void SET(T *__attribute__((may_alias)) p, T val) {
    *p=val;
}
template <typename T> T GET(T *__attribute__((may_alias)) p) {
    return *p;
}
#else
#ifdef USE_MEMCPY
#include <string.h>
#define _SET(p,val,line) \
  ({ typeof(val) _temp_##line = (val); \
       memcpy((void*)(p),(void*)&_temp_##line,sizeof(_temp_##line)); }) 
#define _GET(p,line) \
  ({ typeof(*(p)) _temp_##line; \
       memcpy((void*)&_temp_##line,(void*)(p),sizeof(_temp_##line)); \
       _temp_##line; })

#define SET(p,val) _SET(p,val,__LINE__)
#define GET(p) _GET(p,__LINE__)
#else /* no memcpy */
#ifdef USE_PACKED
#define SET(p,val) (((struct { typeof(val) x __attribute__((packed)); } __attribute__((may_alias))*)p)->x=(val))
#define GET(p) (((struct { typeof(*p) x __attribute__((packed)); } __attribute__((may_alias))*)p)->x)
#else
#define SET(p,val) (*((typeof(val) __attribute__((may_alias))*)p)=(val))
#define GET(p) (*((typeof(*p) __attribute__((may_alias))*)p))
#endif
#endif
#endif

次に、次のように関数を記述できます。

int q(int *p) {
    SET(p,GET(p)+12);
    return p[0];
}
于 2013-04-25T08:59:40.750 に答える