C语言结构体使用memcmp比较是否相等

标题C语言对结构体使用memcmp

在软件开发中,经常会遇到对字符串,内存比较的处理,我们通常很少会自己手写一遍比较函数,会调用C语言库函数进行处理,如strcmp,strncmp,memcmp等。
面试的时候,面试官经常会问过类似这样一个题目,这个题目考的内容就是基础的字节对齐问题的扩展,觉得有必要写一下。
问题描述:
有如下结构体:

struct test
{
	int member_a;
	char member_b;
};

问,在32位机器上,sizeof(struct test) = ?
那毫无疑问,答案是8;
很典型的字节对齐问题,再比如将上诉结构体的两个成员变量上下两个数据类型互换之后,结果是多少?就是char在前,int在后。这都是一个类型的问题。这里不展开讲字节对齐问题,有很多大牛讲的已经很详细了。那这个问题的扩展问题是什么呢。如下:
struct test testA,和stauct test testB两个结构体,能否用memcmp比较这两个结构体是否相等,memcmp(testA, testB, sizeof(struct test));?
先不说结果,先写段代码测试一下:

#include <stdio.h>
#include <stdlib.h>

typedef struct Test
{
    int     member_a;
    char    member_b;
}test;

int main(int argc, char **argv)
{
    test *test1 = (test*)malloc(sizeof(test));
    if (!test1)
    {
        printf("alloc fail\n");
        return -1;
    }
    test1->member_a = 0x12345678;
    test1->member_b = 0x01;
    
    test *test2 = (test*)malloc(sizeof(test));
    if (!test2)
    {
        printf("alloc fail\n");
        return -1;
    }
    test2->member_a = 0x12345678;
    test2->member_b = 0x01;
    
    int ret = memcmp(test1, test2, sizeof(test));
    printf("ret = %d\n", ret);
    
    free(test1);
    test1 = NULL;
    
    free(test2);
    test2 = NULL;
    return 0;
}

老样子,编译,执行:
在这里插入图片描述
ret=0;就说明这两个结构体相等,这样看起来没有什么问题。
那么我们回头来看,这个结构体是不是有效的字节数只有sizeof(int)+sizeof(char)=5,但是sizeof(struct test) = 8, 那么这相差的3个字节去哪了,我们知道malloc是不会对申请的内存进行初始化的,那么如果这三个字节之前的地址有别的内容的话,这里是不是就会出现问题?我们换一种思路,既然这个结构体有效部分只有5个字节,那么其他的三个字节是不是就可以任意处理了?操作一把,在申请到内存之后,把结构体初始化一下,稍作修改:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


typedef struct Test
{
    int     member_a;
    char    member_b;
}test;

int main(int argc, char **argv)
{
    test *test1 = (test*)malloc(sizeof(test));
    if (!test1)
    {
        printf("alloc fail\n");
        return -1;
    }
    memset(test1, 0, sizeof(test)); //初始化全0
    test1->member_a = 0x12345678;
    test1->member_b = 0x01;
    
    test *test2 = (test*)malloc(sizeof(test));
    if (!test2)
    {
        printf("alloc fail\n");
        return -1;
    }
    memset(test2, 1, sizeof(test)); //初始化全1
    test2->member_a = 0x12345678;
    test2->member_b = 0x01;
    
    int ret = memcmp(test1, test2, sizeof(test));
    printf("ret = %d\n", ret);
    
    free(test1);
    test1 = NULL;
    
    free(test2);
    test2 = NULL;
    return 0;
}

编译、执行:
在这里插入图片描述
是不是就出问题了,但是这个结构体不影响使用,原有的成员变量还是可以正常操作的。只不过这里的memcmp就出问题了。
所以这个问题的答案就是,不能针对这个结构体进行memcmp比较是否相等,有风险。
那么问题又来了,如果我非要使用memcmp来比较呢,要怎么处理?
内心os:我看你是诚心想刁难我胖虎。
好吧,看下memcmp函数原型吧:
在这里插入图片描述
Man pages的关于memcmp的描述,针对开始的n个字节的内存进行比较,记中重点,要考的。上面我们是怎么传参数的, memcmp(test1, test2, sizeof(test)); 这里的第三个参数肯定是8啊,多了3个无关的字节啊。想个办法?当然不建议直接去搞他啊,那要换个结构体还得重新算一遍,万一算错了呢,万一不知道多少位的机器呢。还是保留这个sizeof吧。能不能对结构体操作一波?当然能。
不信你去百度搜一下结构体强制对齐,会出现一大把内容:
我选择其中一种方式,#pragma pack(1) //让编译器对这个结构体1字节对齐, #pragma pack() //取消强制对其。修改代码,如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#pragma pack(1) 
typedef struct Test
{
    int     member_a;
    char    member_b;
}test;
#pragma pack()

int main(int argc, char **argv)
{
    test *test1 = (test*)malloc(sizeof(test));
    if (!test1)
    {
        printf("alloc fail\n");
        return -1;
    }
    memset(test1, 0, sizeof(test)); //初始化全0
    test1->member_a = 0x12345678;
    test1->member_b = 0x01;
    
    test *test2 = (test*)malloc(sizeof(test));
    if (!test2)
    {
        printf("alloc fail\n");
        return -1;
    }
    memset(test2, 1, sizeof(test)); //初始化全1
    test2->member_a = 0x12345678;
    test2->member_b = 0x01;
    
    printf("sizeof(test) = %d\n", sizeof(test));
    
    int ret = memcmp(test1, test2, sizeof(test));
    printf("ret = %d\n", ret);
    
    free(test1);
    test1 = NULL;
    
    free(test2);
    test2 = NULL;
    return 0;
}

编译运行:
在这里插入图片描述
完成,强制对齐的方式还有__attribute__,这里不展开讲了,小伙伴们可以自己去学习一下,溜了溜了。如果面试官再问你这个题目,知道怎么回答了吧。
attribute比较强大,只是再别人的代码中看见过,自己至今也是没用过,等抽空学习一下再来说这个吧。

发布了9 篇原创文章 · 获赞 5 · 访问量 1379

猜你喜欢

转载自blog.csdn.net/weixin_34153142/article/details/104759932