Làm thế nào để bạn so sánh hai trường hợp của cấu trúc cho sự bình đẳng trong tiêu chuẩn C?
Làm thế nào để bạn so sánh hai trường hợp của cấu trúc cho sự bình đẳng trong tiêu chuẩn C?
Câu trả lời:
C cung cấp không có phương tiện ngôn ngữ để làm điều này - bạn phải tự làm và so sánh từng thành viên cấu trúc theo thành viên.
0.0, -0.0 NaN
là một vấn đề với memcmp()
. Các con trỏ khác nhau trong biểu diễn nhị phân có thể trỏ đến cùng một vị trí (ví dụ: DOS: seg: offset) và do đó là bằng nhau. Một số hệ thống có nhiều con trỏ null so sánh như nhau. Tương tự đối với che khuất int
với loại -0 và dấu phẩy động với bảng mã dự phòng. (Intel long double, binary64, v.v.) Những vấn đề này không tạo ra sự khác biệt calloc()
hay không sử dụng hoặc đệm.
==
không hoạt động với các cấu trúc (như tôi), vui lòng xem stackoverflow.com/questions/46995631/
Bạn có thể bị cám dỗ để sử dụng memcmp(&a, &b, sizeof(struct foo))
, nhưng nó có thể không hoạt động trong mọi tình huống. Trình biên dịch có thể thêm không gian bộ đệm căn chỉnh vào một cấu trúc và các giá trị được tìm thấy tại các vị trí bộ nhớ nằm trong không gian bộ đệm không được đảm bảo là bất kỳ giá trị cụ thể nào.
Nhưng, nếu bạn sử dụng calloc
hoặc memset
kích thước đầy đủ của các cấu trúc trước khi sử dụng chúng, bạn có thể làm một nông so với memcmp
(nếu cấu trúc của bạn chứa con trỏ, nó sẽ phù hợp với chỉ nếu địa chỉ con trỏ đang trỏ tới đều giống nhau).
memcmp
điều kiện bộ nhớ đã bị xóa trước. Mà gần làm việc nhưng không đúng. Tất nhiên, câu hỏi cũng không định nghĩa "đẳng thức", vì vậy nếu bạn đặt nó có nghĩa là "đẳng thức byte khôn ngoan của biểu diễn đối tượng" thì memcmp
thực hiện chính xác điều đó (cho dù bộ nhớ có bị xóa hay không).
Nếu bạn làm điều đó nhiều, tôi sẽ đề nghị viết một hàm so sánh hai cấu trúc. Bằng cách đó, nếu bạn thay đổi cấu trúc, bạn chỉ cần thay đổi so sánh ở một nơi.
Về cách thực hiện .... Bạn cần so sánh từng yếu tố riêng lẻ
Bạn không thể sử dụng memcmp để so sánh các cấu trúc cho sự bình đẳng do các ký tự đệm ngẫu nhiên tiềm năng giữa các trường trong các cấu trúc.
// bad
memcmp(&struct1, &struct2, sizeof(struct1));
Ở trên sẽ thất bại cho một cấu trúc như thế này:
typedef struct Foo {
char a;
/* padding */
double d;
/* padding */
char e;
/* padding */
int f;
} Foo ;
Bạn phải sử dụng so sánh thành viên khôn ngoan để được an toàn.
@Greg đúng là người ta phải viết các hàm so sánh rõ ràng trong trường hợp chung.
Có thể sử dụng memcmp
nếu:
NaN
.-Wpadded
với tiếng kêu để kiểm tra điều này) HOẶC các cấu trúc được khởi tạo rõ ràng với memset
lúc khởi tạo.BOOL
) có các giá trị riêng biệt nhưng tương đương.Trừ khi bạn đang lập trình cho các hệ thống nhúng (hoặc viết thư viện có thể được sử dụng trên chúng), tôi sẽ không lo lắng về một số trường hợp góc trong tiêu chuẩn C. Sự phân biệt con trỏ gần và xa không tồn tại trên bất kỳ thiết bị 32 hoặc 64 bit nào. Không có hệ thống không nhúng mà tôi biết có nhiềuNULL
con trỏ.
Một tùy chọn khác là tự động tạo các hàm bằng. Nếu bạn đặt các định nghĩa cấu trúc của bạn ra một cách đơn giản, có thể sử dụng xử lý văn bản đơn giản để xử lý các định nghĩa cấu trúc đơn giản. Bạn có thể sử dụng libclang cho trường hợp chung - vì nó sử dụng cùng một lối vào như Clang, nên nó xử lý tất cả các trường hợp góc chính xác (chặn lỗi).
Tôi chưa thấy một thư viện tạo mã như vậy. Tuy nhiên, nó xuất hiện tương đối đơn giản.
Tuy nhiên, đó cũng là trường hợp các hàm bình đẳng được tạo ra như vậy thường làm sai ở cấp ứng dụng. Ví dụ, hai UNICODE_STRING
cấu trúc trong Windows nên được so sánh nông hay sâu?
memset
, v.v. không đảm bảo giá trị của các bit đệm sau khi ghi thêm vào một thành phần cấu trúc, xem: stackoverflow.com/q/52684192/689161
Lưu ý rằng bạn có thể sử dụng memcmp () trên các vị trí không tĩnh mà không phải lo lắng về phần đệm, miễn là bạn không khởi tạo tất cả các thành viên (cùng một lúc). Điều này được xác định bởi C90:
{0, }
cũng sẽ không có bất kỳ byte đệm nào?
Nó phụ thuộc vào việc câu hỏi bạn đang hỏi là:
Để tìm hiểu xem chúng có phải là cùng một đối tượng hay không, so sánh các con trỏ với hai cấu trúc cho sự bằng nhau. Nếu bạn muốn tìm hiểu chung nếu chúng có cùng giá trị, bạn phải làm một so sánh sâu. Điều này liên quan đến việc so sánh tất cả các thành viên. Nếu các thành viên là con trỏ đến các cấu trúc khác, bạn cũng cần phải truy cập vào các cấu trúc đó.
Trong trường hợp đặc biệt khi các cấu trúc không chứa con trỏ, bạn có thể thực hiện một memcmp để thực hiện so sánh từng bit dữ liệu chứa trong mỗi dữ liệu mà không cần phải biết dữ liệu có nghĩa là gì.
Hãy chắc chắn rằng bạn biết "bằng" nghĩa là gì đối với mỗi thành viên - điều này rõ ràng đối với ints nhưng tinh tế hơn khi nói đến các giá trị dấu phẩy động hoặc các loại do người dùng xác định.
memcmp
không so sánh cấu trúc, memcmp
so sánh nhị phân và luôn có rác trong cấu trúc, do đó nó luôn xuất hiện sai khi so sánh.
So sánh yếu tố theo yếu tố an toàn và không thất bại.
Nếu các cấu trúc chỉ chứa nguyên thủy hoặc nếu bạn quan tâm đến sự bình đẳng nghiêm ngặt thì bạn có thể làm một cái gì đó như thế này:
int my_struct_cmp (const struct my_struct * lhs, const struct my_struct * rhs) { return memcmp (lhs, rsh, sizeof (struct my_struct)); }
Tuy nhiên, nếu các cấu trúc của bạn chứa các con trỏ tới các cấu trúc hoặc công đoàn khác thì bạn sẽ cần phải viết một hàm so sánh đúng các nguyên hàm và thực hiện các cuộc gọi so sánh với các cấu trúc khác khi thích hợp.
Tuy nhiên, hãy lưu ý rằng bạn nên sử dụng bộ nhớ (& a, sizeof (struct my_struct), 1) để loại bỏ phạm vi bộ nhớ của các cấu trúc như là một phần của khởi tạo ADT của bạn.
Ví dụ tuân thủ này sử dụng phần mở rộng trình biên dịch gói #pragma từ Microsoft Visual Studio để đảm bảo các thành viên cấu trúc được đóng gói chặt chẽ nhất có thể:
#include <string.h>
#pragma pack(push, 1)
struct s {
char c;
int i;
char buffer[13];
};
#pragma pack(pop)
void compare(const struct s *left, const struct s *right) {
if (0 == memcmp(left, right, sizeof(struct s))) {
/* ... */
}
}