结构体变量之间的比较和赋值原理

时间:2022-11-17 14:00:00

        结构体变量之间可以直接赋值我想大家都知道了。但结构体变量之间可以做比较吗?答案肯定是不行的,因为比较符号只作用于基本数据类型。如果是用C++或者Java来编程时遇到结构体变量之间的比较,那还好办直接对操作符重载就可以了。但如果是用C语言来编程遇到它呢?很多人说那可以自己写个函数啊,自己想怎么实现就怎么实现,况且写个结构体变量之间的比较程序又不是什么难事。但我想问的是你遇到的结构体里面的成员才多少个?如果是一个结构体中包含多个结构体(而结构体中又包含了结构体,比如ovs中的key值)还有多个共同体,那请问你还会想要自己写个比较程序吗?我想如果你要写那个比较程序至少得200行左右吧,而且还要考虑共用体。所以如果结构体比较复杂的,我们可以用下面的方法来比较,而不必自己去写个程序。

        C语言虽然没有面向对象那种对符号的重载功能,但它更为霸气:可以直接操作内存。说到这里我想大家都清楚怎么比较结构体变量了。对!就是用内存比较:memcmp()函数;下面只说下memcmp()函数的原型和功能。函数原型:int memcmp(const void *buf1, const void *buf2, unsigned int count);具体实现可以网上搜索下,这里就不贴出来了。函数的实现功能:就是把buf1和buf2所指向的内存数据都强转为   (char)(*buf1) 和  (char)(*buf2)进行比较,直到区分出大小或者比较完count个字节。这样一分析也指出了用memcmp()函数对结构体变量间比较的两个缺陷。

       第一个缺陷:填充字段问题。因为是内存比较,每个字节都要比较,而结构体变量是有填充字节的(即对齐问题)详细的见:面试常见考题:结构体成员在内存中分配与对齐。所以结构体间的填充字节要都相等(最好的方法就是填充字节都设置为0),这样才不影响结构体变量之间的比较。解决方案是:每次声明定义一个结构体变量都用memset()函数让这个变量的所有字段都设置为0(也可以为其他数,但最好为0)。因为memset()函数也是对内存中的每个字节设定值得。

       第二个缺陷:是结构体里面包含字符串不好判断。因为字符串之间没什么大小比较的,当然了,如果化作字符来比较对你所要的结果没影响也是可以的。还有种情况:假设结构体里面有个字符指针,指向网卡名称的。变量a里面的指针指向字符数组eth_a[],而变量b里面的指针指向字符数组eth_b[] ,但是eth_a[]和eth_b[]里面存放的都是同一个网卡名称。那这情况下就是比较不出来了。因为里面涉及到指针问题

        所以用memcmp()函数来比较2个结构体变量还是要小心点,下面贴个小程序:

        结构体变量之间的比较和赋值原理

        这里我特意为第一个缺陷做了下实验,t1里面的填充字段我全部设置为1,而t2里面的填充字段我都设置为0.其他成员数据都相同。最后用memcmp()函数比较的结果肯定是不相等了。

       结构体变量之间的赋值原理是什么?t1 = t2;把t2的值赋值给了t1,那么是怎么赋值的呢?t1.C = t2.C;  t1.I = t2.I;  t1.ST = t2.ST;是这样赋值的吗?其实不是的。看第27行和第28行代码:如果是成员间赋值的那么第27行代码就是多余的了,因为t1变量里的每个字节都是1。并且第28行的打印应该还是不相等的(因为填充字段不相等)。但事实却不是这样。第28行代码打印的是相等的,反过来说就是不是单纯的成员间的赋值,而是内存拷贝了。t1 = t2把t2的填充字段和成员字段都赋值给了t1.所以总的来说结构体变量间的赋值实则上是内存拷贝。把填充字段和成员变量都拷贝到新变量中。(可能讲的有点乱,总的来说就是看第28行的打印结果来分析赋值原理。如果相等那么就是把填充字段一起赋值过去了;如果不相等那么就是单纯的结构体成员之间的赋值,不涉及填充字段)下面贴出运行的结果:

         结构体变量之间的比较和赋值原理

        根据打印结果可以知道赋值原理其实就是内存拷贝,把填充字段一起拷贝过去了。