1. 示例一

先看下如下代码,思考一下,结果是输出a == b还是a != b

 1#include <stdio.h>
 2#include <string.h>
 3
 4struct test_type {
 5    char name[10];
 6    int i;
 7    long l;
 8};
 9
10int main(void)
11{
12    struct test_type a = {
13        "test", 1, 2
14    };
15    struct test_type b;
16
17    b.i = a.i;
18    b.l = a.l;
19    strcpy(b.name, a.name);
20
21    if (0 == memcmp(&a, &b, sizeof(struct test_type))) {
22        printf("a == b\n");
23    } else {
24        printf("a != b\n");
25    }
26
27    return 0;
28}

1.1. 结果及分析

实际结果很可能是a != b

注意到strcpy(b.name, a.name),由于a.name"test",字符串长度比10要小,strcpy只是复制了a.name的一部分到b.name,所以两者会存在不相等的情况。

2. 示例二

我们把strcpy(b.name, a.name)改成memcpy(b.name, a.name, sizeof(a.name)),来看一下,代码如下。

 1#include <stdio.h>
 2#include <string.h>
 3
 4struct test_type {
 5    char name[10];
 6    int i;
 7    long l;
 8};
 9
10int main(void)
11{
12    struct test_type a = {
13        "test", 1, 2
14    };
15    struct test_type b;
16
17    b.i = a.i;
18    b.l = a.l;
19    memcpy(b.name, a.name, sizeof(a.name));
20
21    if (0 == memcmp(&a, &b, sizeof(struct test_type))) {
22        printf("a == b\n");
23    } else {
24        printf("a != b\n");
25    }
26
27    return 0;
28}

2.1. 结果及分析

然而,实际结果很可能还是a != b

这里涉及到编译器对结构体的处理,为了提高访问性能,编译器会对结构体成员地址进行对齐。对于64位系统来说,int型变量的地址通常要4字节对齐,long型变量的地址通常要8字节对齐。而name数组大小是10,为了满足4字节对齐,i前要留出2字节的空洞。而空洞的内容是不确定的,这就导致了对比结果显示a != b

不过要注意的是,大多数编译器对long型变量也是4字节对齐,所以l前通常不会有空洞。

3. 总结

在编码中,如果要使用memcmp来比较结构体,在声明变量时,要保证使用memset来进行初始化,否则就不用直接使用memcmp来进行比较。