首页 > 编程知识 正文

可以用memcmp进行结构体的比较吗,c语言 memcmp

时间:2023-05-05 15:47:18 阅读:257431 作者:3811

标题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 failn"); return -1; } test1->member_a = 0x12345678; test1->member_b = 0x01; test *test2 = (test*)malloc(sizeof(test)); if (!test2) { printf("alloc failn"); return -1; } test2->member_a = 0x12345678; test2->member_b = 0x01; int ret = memcmp(test1, test2, sizeof(test)); printf("ret = %dn", 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 failn"); 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 failn"); 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 = %dn", 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 failn"); 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 failn"); return -1; } memset(test2, 1, sizeof(test)); //初始化全1 test2->member_a = 0x12345678; test2->member_b = 0x01; printf("sizeof(test) = %dn", sizeof(test)); int ret = memcmp(test1, test2, sizeof(test)); printf("ret = %dn", ret); free(test1); test1 = NULL; free(test2); test2 = NULL; return 0;}

编译运行:

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

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。