Giả sử tôi có một tập tin mã nguồn mẫu, test.c, mà tôi đang biên soạn như vậy:C khắc phục những hạn chế răng cưa (? Đoàn)
$ gcc -Wall -03
thử nghiệm. c trông giống như thế này ..
/// 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
chúng ta hãy cũng nói rằng tôi chấp nhận những hạn chế rằng nếu bạn vượt qua trong hai con trỏ chồng chéo, bạn sẽ có được tái xác định sults.
Tôi đã thử một cái gì đó như thế này (tưởng tượng các macro được định dạng đúng với dòng mới xuyệc ngược thoát vào cuối mỗi dòng)
#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]
})
nhưng khi tôi dereference một trong vĩ mô (a [ 0] < b [0]) Tôi nhận được thông báo "quy định hội nghị chấm dứt vi phạm nghiêm ngặt các quy tắc bí danh" từ gcc
Tôi đã nghĩ rằng bạn phải sử dụng các công đoàn để tham khảo một nơi duy nhất trong bộ nhớ theo hai cách khác nhau, vì vậy tiếp theo tôi đã thử một cái gì đó như
#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
})
Ngoại trừ việc tôi nhận được lỗi chính xác giống như trình biên dịch về quy tắc bí danh nghiêm ngặt.
Vì vậy: có cách nào để thực hiện việc này mà không vi phạm nghiêm ngặt bí danh không, thực tế là COPYING bộ nhớ?
(may_alias đếm doesnt, nó chỉ cho phép bạn bỏ qua các quy tắc nghiêm ngặt-aliasing)
EDIT: sử dụng memcmp để làm điều này. Tôi đã bắt kịp các quy tắc bí danh và không nghĩ về nó.
Để sử dụng công đoàn theo cách phù hợp tiêu chuẩn, bạn chỉ được phép đọc từ thành viên mà bạn đã viết lần cuối. –
@Kerrek: không đúng - C99 cho phép loại thông qua các công đoàn, một chú thích đề cập rõ ràng điều này đã được thêm vào với TC3; tuy nhiên, mã của Todd vẫn không chính xác ... – Christoph
@Christoph: C1x thậm chí còn tốt hơn, phụ lục J (UB) là cố định, cho phép đọc các byte tương ứng với thành viên viết cuối cùng (rõ ràng là mục đích trong C99, nhưng dường như phụ lục J bị bỏ qua sau đó). – ninjalj