Chinaunix

标题: 为什么判断结构体相等要这么复杂呢? [打印本页]

作者: 77h2_eleven    时间: 2008-07-19 14:24
标题: 为什么判断结构体相等要这么复杂呢?
为什么不能直接 == 呢???
作者: 77h2_eleven    时间: 2008-07-19 14:25
我是说:为什么可以用 = 赋值,却不可以用 == 判断相等?
这才是我疑惑的~~
作者: scutan    时间: 2008-07-19 14:33
原帖由 77h2_eleven 于 2008-7-19 14:24 发表
为什么不能直接 == 呢???

对于C语言来说,它的结构体名称其实只是代表它成员变量的第一个元素。
比如说

  1. struct sa
  2. {
  3. int a;
  4. char buf[10];
  5. };

  6. struct sa ss;

  7. 那么如果调用printf("%d\n", ss);与调用printf("%d\n", ss.a)的效果是一样的。
复制代码

所以不能够用这种方法来比较。
作者: MMMIX    时间: 2008-07-19 14:33
原帖由 77h2_eleven 于 2008-7-19 14:25 发表
我是说:为什么可以用 = 赋值,却不可以用 == 判断相等?

因为 C 就是那么规定的。btw,可能他们觉得这种比较不常用,也无法高效的实现。
作者: scutan    时间: 2008-07-19 14:35
而且结构体里面可能还有指针,你该如何判断两个指针是否相同,是根据指针所指向的内容来判断还是仅仅根据指针的值来判断。也是需要程序员自己来定义的。
作者: MMMIX    时间: 2008-07-19 14:40
原帖由 scutan 于 2008-7-19 14:33 发表

对于C语言来说,它的结构体名称其实只是代表它成员变量的第一个元素。

其实最真实的原因是无法对结构体比较提供高效的实现。在 C 中,结构体可能有填充位,这些填充位的值是未定义的,因此结构体的比较就只能是逐个比较其成员,而这种比较方式的效率是很低的(例如碰到很大的结构体),这和  C 追求的高效背道而驰。另外,由于结构体比较这种需求比较少,强迫编译器去支持就不应该了。

但是结构体赋值就不同了,该操作实际上就是内存拷贝,这个在许多机器上都可以很高效的实现。

btw,这个问题可以看下 ISO C Rationale
作者: 77h2_eleven    时间: 2008-07-19 14:44
原帖由 MMMIX 于 2008-7-19 14:40 发表

其实最真实的原因是无法对结构体比较提供高效的实现。在 C 中,结构体可能有填充位,这些填充位的值是未定义的,因此结构体的比较就只能是逐个比较其成员,而这种比较方式的效率是很低的(例如碰到很大的结构体 ...

多谢LD,真是高手。
也就是说,由于赋值可以用memcpy等函数实现,但是比较却不能用memcmp等函数实现。
所以,NNGX,费力不讨好,干脆就不实现了~~~
作者: sun20082002    时间: 2008-07-19 14:52
可以考虑将 == 重载,或者写一个比较函数,在比较很多的情况下,可以省事:wink:
作者: prolj    时间: 2008-07-19 15:19
标题: 回复 #8 sun20082002 的帖子
C++就是那么重载的,可是C不行
作者: sun20082002    时间: 2008-07-19 15:28
标题: 回复 #9 prolj 的帖子
c的不熟悉了.原来如此,那让我碰到c的,写一个比较用途的全局函数,就ok了吧?
作者: Godbach    时间: 2008-07-19 15:38
一般在什么时候用到判断结构体是否相等呢?
作者: erqb    时间: 2008-07-19 15:45
标题: 回复 #1 77h2_eleven 的帖子
你碰到这个需求了,就提出了这个疑问。我想你的设计有问题或不合理。
C语言每次加入新东西时都很谨慎,新东西加入C前必须考虑其是否实用,是否符合常理,是否符合人的思维习惯,所以C语言非常精炼,没有丝毫杂质。相反,C++的就很臃肿愚蠢。

[ 本帖最后由 erqb 于 2008-7-19 15:47 编辑 ]
作者: blizzard213    时间: 2008-07-19 15:58
原帖由 erqb 于 2008-7-19 15:45 发表
你碰到这个需求了,就提出了这个疑问。我想你的设计有问题或不合理。
C语言每次加入新东西时都很谨慎,新东西加入C前必须考虑其是否实用,是否符合常理,是否符合人的思维习惯,所以C语言非常精炼,没有丝毫杂 ...


说c好就可以了
没有必要连带批判c++
存在即是合理

c++的设计者的编程经验比你的年龄还要长
作者: jigloo    时间: 2008-07-19 16:00
这个人是OIOIC的马甲,楼上不必理会。
作者: yourantianya    时间: 2008-07-19 16:06
结构体里面可能有指针,不能用这种方法比较
作者: erqb    时间: 2008-07-19 16:08
标题: 回复 #13 blizzard213 的帖子
给你纠正一下,“存在是必然”是对的,“存在即是合理”是错的,呵呵,学东西了吧。
“c++的设计者的编程经验比你的年龄还要长”不是我不可以批判C++的理由吧,呵呵,又学东西了吧。
作者: erqb    时间: 2008-07-19 16:09
标题: 回复 #14 jigloo 的帖子
OIOIC的马甲,什么意思?
作者: blizzard213    时间: 2008-07-19 16:10
原帖由 erqb 于 2008-7-19 16:08 发表
给你纠正一下,“存在是必然”是对的,“存在即是合理”是错的,呵呵,学东西了吧。
“c++的设计者的编程经验比你的年龄还要长”不是我不可以批判C++的理由吧,呵呵,又学东西了吧。


可以锁帖了
作者: MMMIX    时间: 2008-07-19 16:10
原帖由 77h2_eleven 于 2008-7-19 14:44 发表

也就是说,由于赋值可以用memcpy等函数实现,但是比较却不能用memcmp等函数实现。

嗯,就是这么个意思。当然,在具体实现的时候编译器完全可以根据具体 cpu 提供的指令进行优化(如直接生成实现此功能的汇编指令),像 memcpy 这种函数一般都是经过高度优化的,在某些情况下直接就是用汇编写的。

[ 本帖最后由 MMMIX 于 2008-7-19 16:12 编辑 ]
作者: MMMIX    时间: 2008-07-19 16:13
原帖由 blizzard213 于 2008-7-19 16:10 发表


可以锁帖了

单就你引用的那两句来说,还是蛮有道理的。
作者: erqb    时间: 2008-07-19 16:18
memcmp不就是用来比较内存的么,怎么又不能比较了。

[ 本帖最后由 erqb 于 2008-7-19 16:19 编辑 ]
作者: zx_wing    时间: 2008-07-19 17:33
原帖由 MMMIX 于 2008-7-19 16:10 发表

嗯,就是这么个意思。当然,在具体实现的时候编译器完全可以根据具体 cpu 提供的指令进行优化(如直接生成实现此功能的汇编指令),像 memcpy 这种函数一般都是经过高度优化的,在某些情况下直接就是用汇编写的。

删了,我说错了

[ 本帖最后由 zx_wing 于 2008-7-19 17:36 编辑 ]
作者: converse    时间: 2008-07-19 17:51
结构体赋值的时候只是简单的内存copy,它不关心里面的内容如何;但是,判断相等时就复杂了,假如结构体中有指针,而原本的意思是比较指针的内容是否相等,但是如果按照上面内存copy的语意来解释就成了比较指针是否相等了.另外,结构体中可能有为了填充,对齐而提供的内容,对这些部分进行内存比较显然也是不可理的.基于这些,C中不提供=操作符用于比较结构体是否相等,而把这个权利留给了程序员.

[ 本帖最后由 converse 于 2008-7-19 20:33 编辑 ]
作者: THEBEST    时间: 2008-07-19 18:34
原帖由 scutan 于 2008-7-19 14:33 发表

对于C语言来说,它的结构体名称其实只是代表它成员变量的第一个元素。
比如说

struct sa
{
int a;
char buf[10];
};

struct sa ss;

那么如果调用printf("%d\n", ss);与调用printf("%d\n", ss.a ...
你这个第一个元素是int没问题,但两个成员换个位置,用%s打印为什么就core呢?结构体名称只是代表它成员变量的第一个元素是个什么意思?
作者: erqb    时间: 2008-07-19 20:19
原帖由 erqb 于 2008-7-19 16:18 发表
memcmp不就是用来比较内存的么,怎么又不能比较了。



用memcmp是不可靠的,比如结构体里有字符数组成员。呵呵,自问自答。
作者: scutan    时间: 2008-07-19 20:41
原帖由 THEBEST 于 2008-7-19 18:34 发表
你这个第一个元素是int没问题,但两个成员换个位置,用%s打印为什么就core呢?结构体名称只是代表它成员变量的第一个元素是个什么意思?


我是这样理解的, 结构体的名称只是代表这个结构体里面成员的第一个变量的基本类型, 也就是说对于前面那个结构体来说, 它仅代表一个 char 类型,
可以用 printf("%c\n", mm); 来打印出buf[0]出来, 但是却不能够打印出整个数组.

之所以core的原因是那条语句的作用就相当于是 char c = 'h'; printf("%s\n", c); 对一个char类型用%s的方式打印, 所以就出了问题.
当然, 我说的那种用法是不合法的. 应该避免.
作者: mik    时间: 2008-07-19 22:09
原帖由 scutan 于 2008-7-19 20:41 发表


我是这样理解的, 结构体的名称只是代表这个结构体里面成员的第一个变量的基本类型, 也就是说对于前面那个结构体来说, 它仅代表一个 char 类型,
可以用 printf("%c\n", mm); 来打印出buf[0]出来, 但是却不能 ...


你的理解是错误的。

用你的例子来说:
struct sa
{
int a;
char buf[10];
};
struct sa ss;
printf("%d\n", ss); 与调用printf("%d\n", ss.a) 的效果是两码事,虽然在这里结果是一样。

用结构体作参数是压整个结构体,这里 ss 参数是压整个 ss 结构, ss.a 是仅传数 ss.a

若 buf 与 a 换一下,错误就能体现出来的。
printf("%s\n", ss);  就将 bu f数组里的值作为指针来求输出,所以产生fault
作者: scutan    时间: 2008-07-19 22:21
原帖由 mik 于 2008-7-19 22:09 发表


你的理解是错误的。

用你的例子来说:
struct sa
{
int a;
char buf[10];
};
struct sa ss;
printf("%d\n", ss); 与调用printf("%d\n", ss.a) 的效果是两码事,虽然在这里结果是一样。

用结构 ...


非常感谢. 学习了!
作者: kumbayaco    时间: 2008-07-19 22:39
原帖由 mik 于 2008-7-19 22:09 发表


你的理解是错误的。

用你的例子来说:
struct sa
{
int a;
char buf[10];
};
struct sa ss;
printf("%d\n", ss); 与调用printf("%d\n", ss.a) 的效果是两码事,虽然在这里结果是一样。

用结构 ...



这个解释太赞了!!用到了好多方面的细节知识。
作者: feiyueheu    时间: 2008-07-19 23:39
C中对运算符的定义就是这样的.有什么办法.
而且C不支持运算符的重载的.
作者: 虑而后能得    时间: 2008-07-20 08:30
标题: 回复 #4 MMMIX 的帖子
呵呵 我也这样想
作者: lllaaa    时间: 2008-07-20 08:38
原帖由 erqb 于 2008-7-19 20:19 发表



用memcmp是不可靠的,比如结构体里有字符数组成员。呵呵,自问自答。


真正的原因帖子最前面的几个回复有。

因为结构体可能因为对齐产生一些空隙。而这些空隙的值是不确定的。直接用memcmp会连这些空隙一起比较而不是只比较结构体成员。
作者: rjgb    时间: 2008-07-20 11:22
标题: 回复 #32 lllaaa 的帖子
那些空隙不是主要原因, 在定义结构体变量时把变量全初始化0就行了. erqb说的结构体里有字符数组成员就不好办了, 字符串结束符后面是什么东西是不能确定的.




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2