Предположим, у меня есть пример исходного файла test.c, который я собираю следующим образом:
$ gcc -03 -Wall
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
Допустим, я принимаю ограничение, что если вы передадите два перекрывающихся указателя, вы получите неопределенные результаты.
Я пробовал что-то вроде этого (представьте, что эти макросы правильно отформатированы с символами новой строки, начинающимися с обратной косой черты в конце каждой строки)
#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 в макросе (a [0]
Я думал, что вы должны были использовать союзы для правильного обращения к одному месту в памяти двумя разными способами, поэтому затем я попробовал что-то вроде
#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, чтобы сделать это. Я увлекся правилами псевдонимов и не думал об этом.