免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
11 [报告]
发表于 2010-01-28 00:55 |显示全部楼层

回复 #45 w_anthony 的帖子

原帖由 w_anthony 于 2010-1-27 09:17 发表
测试了一下,VC7没遵守这规则,不管开不开优化这里都会有Copy Construct,而MinGW不管开不开优化则都没有Copy Construct。

嘿嘿, 换VC8吧~

看这个:
http://msdn.microsoft.com/en-us/library/ms364057(VS.80).aspx

Named Return Value Optimization in Visual C++ 2005

Summary: Shows how the Visual C++ compiler eliminates redundant Copy constructor and Destructor calls in various situations. (12 printed pages)


原帖由 w_anthony 于 2010-1-27 09:17 发表
一般来说可以直接return 构造函数()的理想情况是比较少的


少和多不好定义。 举一些例子吧。  STL里面返回值的函数包括(但不限于):
string的substr是返回值的。
stringstream的 一个str重载。
valarray 的 许多成员。

我随便翻了翻gcc2.9.5(因为我觉得可能对低版本的编译器更需要这些比较恶心的技巧) 和gcc3.4.5所带的stl。
几乎全都使用的"计算式构造函数"。

如果使用C++0x的move语意能够实现, 这些成员就可以依然高效的返回值, 而且不必使用这种比较恶心的技巧。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
12 [报告]
发表于 2010-01-28 00:58 |显示全部楼层

回复 #51 思一克 的帖子

原帖由 思一克 于 2010-1-27 13:09 发表
是的。
返回大结构是愚蠢行为。


能详细解释一下吗? 为什么愚蠢?

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
13 [报告]
发表于 2010-01-28 01:00 |显示全部楼层

回复 #57 pmerofc 的帖子

这不奇怪。 返回结构体是C在标准化时加入的特性。 在那之前, 好像确实存在不可以的编译器。
这个特性的加入, 还引起了不少程序员的反感

btw: 能说说你的看法么?

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
14 [报告]
发表于 2010-01-28 01:36 |显示全部楼层

回复 #61 pmerofc 的帖子

经常看到类似这样的代码: (可能写错了 大致就这么个意思   )
int f(a, b)
      int a,
      int b
{
      ...
}
怎么说呢, 当历史车轮前进的同时, 总是有守旧派的

说到自然的表达思想,有句话但不记得出处了: 代码是给人看的, 只是顺便让机器执行

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
15 [报告]
发表于 2010-01-28 17:15 |显示全部楼层

回复 #64 pmerofc 的帖子

我也不是经常去翻标准的……  做编译器的人才是标准专家
只是有时候希望代码的行为能够有某种保证时, 才去翻翻看有没有这种保证。
比如最近翻到3个比较受用的保证:
1. struct 中可以有padding, 但绝对不会出现在第1个field之前。
2. union中所有field的offset都是0 。
3. ==, !=, < ... 这些操作符的结果都是0或者1 。


我英文也很烂……   6级都没过……
那段话是出自这里吧?

c99 6.5 Expressions p67
2 Between the previous and next sequence point an object shall have its stored value
modified at most once by the evaluation of an expression. Furthermore, the prior value
shall be read only to determine the value to be stored.70)

...

70) This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a[i ] = i;


没看懂……  
我还搜了一些其他资料, 比如这个: http://www.embedded.com/story/OEG20020625S0041

依然没看懂……  觉得有些歧义。 也许是我理解错了……



但是在附录中翻到一个对应的条款, 好像更容易理解一些:
c99 J.2 Undefined behavior p491
— Between two sequence points, an object is modified more than once, or is modified
and the prior value is read other than to determine the value to be stored (6.5).


那个prior真的很关键……  指的是:
1. modify之前
2. sequence point之前

如果是2, 那基本就说得通了。 如果是1……  还是不懂……
然后就困了睡了……


出门寻求场外援助去了
晚上回来看能不能将这这个词理解准确一些……



ident是什么?

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
16 [报告]
发表于 2010-01-28 17:22 |显示全部楼层

回复 #66 w_anthony 的帖子

你看这么理解可行不?

1. 如果功能已经确定, 就是"修改一个已经存在的对象"
那没得说, 肯定是传入该对象的引用或者指针, 而不是返回一个新的值。

比如 replace

2. 如果功能被确定为 "返回一个新对象"
在这种情况下, 将功能改变为"默认创建, 然后修改", 肯定是有损清晰自然的表达。
而且效率也不见得会高。

比如 substr


3. 如果某个需求既可以被设计为1, 又可以被设计为2
这……   就得仔细研究了……
valarray采用的是2 , 而不是1 。 而且是故意这么设计的。 理由我忘了……

[ 本帖最后由 OwnWaterloo 于 2010-1-28 17:24 编辑 ]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
17 [报告]
发表于 2010-01-28 19:23 |显示全部楼层

回复 #72 pmerofc 的帖子

ident好像没有什么特殊含义, 就是为下面要描述的那个东西起一个名字
根据ident是斜体瞎猜的……

类似的就像:
there is a function f ...
f balabala ...

有一个函数f ...
f 啥啥...

let's store the value to a local variable v ...
v balabala ...
将这个值存放到一个局部变量v中 ...
v 啥啥...



呃…… 那个prior……  再研究研究……


不用客气
将这个问题彻底搞清楚对我也有好处
比如以前只能"大致觉得"某些(面试)题很sb, 但其实又很心虚 —— 万一误会它了呢?
彻底弄明白之后, 就可以肯定它们中的一些就是sb

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
18 [报告]
发表于 2010-01-28 21:53 |显示全部楼层

回复 #70 OwnWaterloo 的帖子

场外求助失败     无法得知prior 到底指的什么……
根据给出的例子, 可能是指sequence point之前。 但这种推测肯定是不严谨的, 是由结论去推测过程……

期待大牛了……

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
19 [报告]
发表于 2010-01-28 22:22 |显示全部楼层

回复 #75 w_anthony 的帖子

再换一个角度吧……

比如就是string.replace。 既可以提供返回值的, 也可以提供在一个对象上修改的版本。
(不写模板了, 实际上是个模板)

class string {
public:
      string replace( ... );
static void replace( string& s, ... );
};

那么, 想替换, 并且得到一个新的string, 就可以调用返回值的。
想在既有对象上修改的, 就可以调用传入引用的。

这是2种不同的功能。
当需要一个新对象时 —— 而不管某个特定的函数该如何设计了, 而是从用户的需要来说 —— 返回值可能就会比绕弯去使用引用要快。
当需要在原对象上修改时, 那肯定不能设计为返回值。





"另外如果是DLL导出函数,还是要用1方式,毕竟不同的编译器行为不确定,用2的话MinGW的dll给VC调用就可能会出问题。"
这不是"应该返回值时将其改为创建然后修改"的理由。

这是设计的另一个方面了 —— 是否需要隐藏对象的表示。
如果确实需要, 是不可以创建对象的值, 而只能使用引用的。




这么说吧, 前面一个设计, 可以通过一个问题来得到答案 "你需要获得一个新对象吗?"
如果是, 就返回值; 否则就采用参数。

后面一个设计, 也可以通过一个问题来得到答案 "你要限制按值语意使用对象吗?"
如果是, 连直接创建对象都不可以, 只能通过引用或者指针来创建, 使用, 销毁对象。
在这种情况下, 讨论前一个问题就是无意义的了 —— 本来就不存在(或者不可见)对象的值, 只有引用或指针。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
20 [报告]
发表于 2010-01-28 22:52 |显示全部楼层

回复 #77 pmerofc 的帖子

琢磨出来后麻烦分享一下哦  先谢谢了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP