免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: yazi0127
打印 上一主题 下一主题

[C] 请教:C语言函数的返回值类型能否为结构体? [复制链接]

论坛徽章:
9
摩羯座
日期:2013-08-15 15:18:48狮子座
日期:2013-09-12 18:07:47金牛座
日期:2013-09-16 13:23:09辰龙
日期:2013-10-09 09:03:27白羊座
日期:2013-10-17 13:32:44子鼠
日期:2014-04-23 15:09:38戌狗
日期:2014-09-17 11:37:542015年亚洲杯之韩国
日期:2015-03-26 10:16:442015亚冠之武里南联
日期:2015-08-18 14:55:52
31 [报告]
发表于 2010-01-27 00:05 |只看该作者
原帖由 OwnWaterloo 于 2010-1-26 23:53 发表


你试过没有, 你确定?
23楼的汇编代码你看没有?  哪一个函数会"写"内存???
上面的有vc6、8、9的汇编输出, 你说的VC又是哪个版本?


再者, 只要有一个反例,就可以证明对结构体的返回并不全是采 ...


喂喂,我又没说你,别急啊。。。
我用的VC是VS2003(VC7),此外这个例子只是想反驳某人说的不会产生拷贝而已,注释加在那里也是这个意图。
从反汇编看,O2优化,struct A如果是4字节,用eax返回,8字节用eax+edx返回,确实不是用指针,超过8字节的必定是指针。
好吧,我支持一下你的观点。不过用指针没啥不好的,当然编写者自己要清楚一点原理,对于大结构体至少少一次拷贝。

论坛徽章:
9
摩羯座
日期:2013-08-15 15:18:48狮子座
日期:2013-09-12 18:07:47金牛座
日期:2013-09-16 13:23:09辰龙
日期:2013-10-09 09:03:27白羊座
日期:2013-10-17 13:32:44子鼠
日期:2014-04-23 15:09:38戌狗
日期:2014-09-17 11:37:542015年亚洲杯之韩国
日期:2015-03-26 10:16:442015亚冠之武里南联
日期:2015-08-18 14:55:52
32 [报告]
发表于 2010-01-27 00:09 |只看该作者
原帖由 老手 于 2010-1-26 23:44 发表


请搞清楚再说.


我想我是得再清楚一点,这里的例子举的不好,struct A太小了,结果就是OwnWaterloo,直接用寄存器了,看不出你所说的“拷贝无法自圆其说论”,改成
struct A
{
     int i, j, g;
};
就行了。

论坛徽章:
0
33 [报告]
发表于 2010-01-27 00:12 |只看该作者
原帖由 OwnWaterloo 于 2010-1-26 23:59 发表
"以我的代码"并不能证明什么。

看29楼, 只要能够举出一个没有采用隐式指针参数的反例, 就可以说明这个结论是错误的:



结论是 : 并不都是这样。

上面5份代码, 全都是通过寄存器返回的, 没有写 ...



gcc你我编译的结果相差甚远 . 我编译的支持我的观点.

相信你的VC编译结果 : VC上小结构 , 可以不用隐式指针传递.

也就是如何处理与编译器有关.

论坛徽章:
0
34 [报告]
发表于 2010-01-27 00:22 |只看该作者
原帖由 w_anthony 于 2010-1-27 00:09 发表


我想我是得再清楚一点,这里的例子举的不好,struct A太小了,结果就是OwnWaterloo,直接用寄存器了,看不出你所说的“拷贝无法自圆其说论”,改成
struct A
{
     int i, j, g;
};
就行了。


你这想说明什么?!

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
35 [报告]
发表于 2010-01-27 00:23 |只看该作者

回复 #31 w_anthony 的帖子

我就缺vc7 ……   vc10都有, 只是不常用……
感觉它是一个过度版本, 用户不如vc6广, 对标准支持度又不如vc8以后的版本……

支持谁其实不重要, 就像你说的, 人总是会犯错的。
所以, 我选择支持真理, 即使是在当前认知条件下狭隘的真理。


并且, 使用指针并不一定会产生高效代码。 但使得代码变得难看是肯定的。

例如, 不能很自然的这么写:
point p = make_point(x, y);

而是要分为2步:
point p;
make_point(&p, x, y);

呃, 我觉得后者不自然……  这个是口味问题。



就效率来说:

T make_T( parameter ) {
      return T( arguments ); // 一个构造函数
}

那么:
T v = make_T(arguments );

有可能就是:
T v; // 没有初始化
new (&v)  T(arguments); // 一次初始化

这是具名返回值优化。 可以直接将返回值, 替换为函数中的具名返回对象。
而这个返回值, 在调用前是一个没有初始化的对象 —— 整个调用正好是它的初始化。



如果显示的使用指针(或者引用)
void make_T(T* t, parameter ) {
      *t = T(parameter) ; // 一次构造, 一次拷贝
}

T v; // 传递之前, 还有一次默认构造
make_T(&t, arguments);
无论编译器能对这种代码优化到什么程度, 它的语意和上面是不同的, 语意上始终要多1次默认构造和拷贝。

[ 本帖最后由 OwnWaterloo 于 2010-1-27 00:25 编辑 ]

论坛徽章:
9
摩羯座
日期:2013-08-15 15:18:48狮子座
日期:2013-09-12 18:07:47金牛座
日期:2013-09-16 13:23:09辰龙
日期:2013-10-09 09:03:27白羊座
日期:2013-10-17 13:32:44子鼠
日期:2014-04-23 15:09:38戌狗
日期:2014-09-17 11:37:542015年亚洲杯之韩国
日期:2015-03-26 10:16:442015亚冠之武里南联
日期:2015-08-18 14:55:52
36 [报告]
发表于 2010-01-27 00:27 |只看该作者
原帖由 老手 于 2010-1-27 00:22 发表


你这想说明什么?!


你认为是:
void func(struct A* p)
{
    p->i = 0;
}


但是实际上是:
void func(struct A* p)
{
    struct A a;
    a.i = 0;
    *p = a;        //拷贝发生在这里

}


所以我试着去代替某人“自圆其说”一下存在“拷贝”这个事件,我是否是“漏洞百出”?

论坛徽章:
9
摩羯座
日期:2013-08-15 15:18:48狮子座
日期:2013-09-12 18:07:47金牛座
日期:2013-09-16 13:23:09辰龙
日期:2013-10-09 09:03:27白羊座
日期:2013-10-17 13:32:44子鼠
日期:2014-04-23 15:09:38戌狗
日期:2014-09-17 11:37:542015年亚洲杯之韩国
日期:2015-03-26 10:16:442015亚冠之武里南联
日期:2015-08-18 14:55:52
37 [报告]
发表于 2010-01-27 00:34 |只看该作者
原帖由 OwnWaterloo 于 2010-1-27 00:23 发表
我就缺vc7 ……   vc10都有, 只是不常用……
感觉它是一个过度版本, 用户不如vc6广, 对标准支持度又不如vc8以后的版本……

支持谁其实不重要, 就像你说的, 人总是会犯错的。
所以, 我选择支持真理, ...


T make_T( parameter ) {
      return T( arguments ); // 一个构造函数
}

举这个例子,不是以偏概全么?
这么return确实是没有拷贝过程的,但是一个复杂的函数结果是返回结构体的话,绝大多数不会这么理想,中间会有临时变量定义,再return临时变量。
而且现在说的是结构体,如果是类的话,用return临时变量的写法,构造函数的调用次数也不会少。

[ 本帖最后由 w_anthony 于 2010-1-27 00:35 编辑 ]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
38 [报告]
发表于 2010-01-27 00:37 |只看该作者

回复 #33 老手 的帖子

原帖由 老手 于 2010-1-27 00:12 发表
相信你的VC编译结果 : VC上小结构 , 可以不用隐式指针传递.

你这话说的   我没必要捏造一个VC的结果出来吧…………


原帖由 老手 于 2010-1-27 00:12 发表
也就是如何处理与编译器有关.


就是这样。 其实上面的gcc是mingw。 依然是没有写内存, 直接寄存器返回。
不过我也确实没有换到ubuntu上去试过这样的代码。 可能那上面会不同。

"显示使用指针传递" 并不一定比直接返回结构并让编译器安插隐式参数来得高效, 这点上我们意见还是相同的。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
39 [报告]
发表于 2010-01-27 00:48 |只看该作者

回复 #37 w_anthony 的帖子

嗯, 那确实是一个很极端的例子 ……

论坛徽章:
0
40 [报告]
发表于 2010-01-27 01:20 |只看该作者

回复 #36 w_anthony 的帖子

目前的结论是,在对待小结构的处理上,各编译器有所不同 ; 大结构用隐式指针传递 .
只要需要 , 完全可以大胆直接返回结构.

至于你说的
void func(struct A* p)
{
    struct A a;
    a.i = 0;
    *p = a;        //拷贝发生在这里

}

即便不是"漏洞百出",也一样以偏盖全了.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP