次のようにコンパイルするサンプル ソース ファイル test.c があるとします。
$ gcc -03 -ウォール
test.c は次のようになります。
/// CMP128(x, y)
//
// arguments
// x - any pointer to an 128-bit int
// y - any pointer to an 128-bit int
//
// returns -1, 0, or 1 if x is less than, equal to, or greater than y
//
#define CMP128(x, y) // magic goes here
// example usages
uint8_t A[16];
uint16_t B[8];
uint32_t C[4];
uint64_t D[2];
struct in6_addr E;
uint8_t* F;
// use CMP128 on any combination of pointers to 128-bit ints, i.e.
CMP128(A, B);
CMP128(&C[0], &D[0]);
CMP128(&E, F);
// and so on
また、2 つの重複するポインターを渡すと、未定義の結果が得られるという制限を受け入れるとしましょう。
私はこのようなことを試しました(これらのマクロが各行の終わりにバックスラッシュでエスケープされた改行で適切にフォーマットされていると想像してください)
#define CMP128(x, y) ({
uint64_t* a = (void*)x;
uint64_t* b = (void*)y;
// compare a[0] with b[0], a[1] with b[1]
})
しかし、マクロ (a[0] < b[0]) で a を逆参照すると、gcc から「逆参照は厳格なエイリアス規則を破ります」というエラーが表示されます
ユニオンを使用して、メモリ内の 1 つの場所を 2 つの異なる方法で適切に参照する必要があると考えていたので、次のようなことを試しました。
#define CMP128(x, y) ({
union {
typeof(x) a;
typeof(y) b;
uint64_t* c;
} d = { .a = (x) }
, e = { .b = (y) };
// compare d.c[0] with e.c[0], etc
})
ただし、厳密なエイリアシング規則に関して、コンパイラからまったく同じエラーが発生します。
だから:実際にメモリをコピーする以外に、厳密なエイリアスを壊さずにこれを行う方法はありますか?
( may_aliasはカウントされません。厳密なエイリアス規則をバイパスできるようにするだけです)
編集: memcmp を使用してこれを行います。エイリアシングのルールにとらわれてしまい、考えもしませんでした。