[英]Is there a better way to compare two C structs?
假設我聲明了一個 C 結構來保存配置信息,它有很多字段(~30),例如:
struct config {
int a;
int b;
int c;
...
char *str1;
char *str2;
...
};
在不簡單枚舉和比較每個元素的情況下比較兩個結構的最佳方法是什么? 當然我可以使用下面的代碼,但我的問題是,有沒有更簡單的方法來實現這一點?
static int
cmpInstances(struct config *l, struct config *r) {
return (
l->a == r->a &&
l->b == r->b &&
l->c == r->c &&
!strcmp(l->str1, r->str1) &&
!strcmp(l->str2, r->str2)
);
}
有沒有可以做到這一點的宏? 例如: cmpInstancesViaMacro(a,b,c)
將擴展為
l->a == r->a &&
l->b == r->b &&
l->c == r->c
也許一些宏會幫助我們減少代碼行數和所需的工作量:
#define CMP(name) l->name == r->name &&
#define SCMP(name) !strcmp(l->name, r->name) &&
struct config
{
int a;
int b;
int c;
char *str1;
char *str2;
};
static int cmpInstances(struct config *l, struct config *r)
{
return CMP(a) CMP(b) CMP(c) SCMP(str1) SCMP(str2) 1;
}
#undef CMP
#undef SCMP
這里我們定義了一些只取變量名並比較它們的宏。 一個用於 integer 比較 ( CMP
),另一個用於字符串比較 ( SCMP
)。 然后,您可以使用這些宏來比較您的數據並在完成后undef
它們。
感謝 chqrlie 添加1
部分。
在不簡單枚舉和比較每個元素的情況下比較兩個結構的最佳方法是什么?
呈現的方式是最好的。 除了,指針應該指向const
- 沒有被修改。
有沒有更簡單的方法來實現這一點?
呈現的方式是實現它的最簡單的方式,它也是最易讀和不言自明的,易於重構和推理。 任何其他都會增加復雜性並導致維護負擔。
我發現strcmp(...) == 0
.strcmp(...)
更清晰。
可以使用所謂的X 宏的廣義變體。
在問題的示例中,它看起來像這樣:
#define STRUCT \
X_INT(a) \
X_INT(b) \
X_INT(c) \
X_STRING(str1) \
X_STRING(str2)
struct config {
#define X_INT(NAME) int NAME;
#define X_STRING(NAME) char *NAME;
STRUCT
#undef X_INT
#undef X_STRING
};
static int cmpInstances(struct config *l, struct config *r) {
#define X_INT(NAME) l->NAME == r->NAME &&
#define X_STRING(NAME) strcmp(l->NAME, r->NAME) == 0 &&
return STRUCT 1;
#undef X_INT
#undef X_STRING
}
使用此解決方案,只要不更改所使用的類型集,只要更改結構時只需更改STRUCT
宏即可。 結構和 function 將自動保持同步。
如果引入了新的類型,則對應的 X Macros 必須與上面的X_INT
和X_STRING
類似定義。
如果您是該結構的作者,您可以將其布局,這樣就沒有填充, _Static_assert
表示沒有填充(sizeof(whole+struct) == 組件大小的總和),然后如果所有數據都只需使用一個memcmp
調用在結構中。
如果結構具有字符串指針(並且您不能保證具有特定內容的字符串僅存儲在一個位置),則需要單獨執行這些操作。
如果將它們全部放在一起,您將獲得最緊湊的代碼,將它們與相應的char*[]
數組聯合,然后遍歷相應的 arrays 在每一對上調用strcmp
並組合結果(如果所有都是相等)與 rest 的 memcpy。
就像是:
#include <string.h>
struct config {
int m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11,m12,m13,m14,m15,m16;
union {
struct { char *s1,*s2,*s3,*s4,*s5,*s6,*s7,*s8; };
char *strings[8];
};
};
_Static_assert(sizeof(struct config) == sizeof(int)*16+sizeof(char*)*8,"");
int strings_equal(char *const A[], char *const B[], size_t Count){
for(;Count;Count--) if(0!=strcmp(*A++,*B++)) return 0;
return 1;
}
int configs_equal(struct config const *A, struct config const *B){
return 0==memcmp(A,B,sizeof(int)*16)
&& strings_equal(A->strings,B->strings,sizeof(A->strings)/sizeof(A->strings[0]));
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.