#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { int m_Member1; int m_Member2; char m_String[20]; }FUNCTION_STRUCT; FUNCTION_STRUCT ReturnStruct(void) { FUNCTION_STRUCT internalData; internalData.m_Member1 = 1; internalData.m_Member2 = 2; strcpy(&(internalData.m_String[0]), "Hello World!\n"); return internalData; } int main(int argc, char *argv[]) { FUNCTION_STRUCT externalData; externalData = ReturnStruct(); printf("%d, %d, %s", externalData.m_Member1, externalData.m_Member2, &externalData.m_String[0]); system(" ![]() return 0; } |
原帖由 daybreakcx 于 2010-1-26 17:23 发表
结构体返回的话一般来说都不会只有一个成员变量,所以一般返回后需要一个结构体变量接着它的返回值,就像2楼的程序一样,平时我一般都是这么干的,我认为这里就有一次整个结构体的拷贝,不知道你所说的是什么 ...
原帖由 wsw1wsw2 于 2010-1-26 17:40 发表
返回的结构体就是根据该结构的大小,有几个字节拷贝出几个字节。
有怀疑可以看看编译出来的汇编。
C语言中一般不怎么玩,一般是传给函数一个结构体指针,由该函数修改这个结构。如果非要函数返回结构实 ...
FUNCTION_STRUCT ReturnStruct(void) { FUNCTION_STRUCT internalData; internalData.m_Member1 = 1; internalData.m_Member2 = 2; strcpy(&(internalData.m_String[0]), "Hello World!\n"); return internalData; } |
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { int m_Member1; int m_Member2; char m_String[20]; }FUNCTION_STRUCT; void ReturnStruct(FUNCTION_STRUCT *internalData) { internalData->m_Member1 = 1; internalData->m_Member2 = 2; strcpy(internalData->m_String, "Hello World!\n"); } int main(int argc, char *argv[]) { FUNCTION_STRUCT externalData; ReturnStruct(&externalData); printf("%d, %d, %s", externalData.m_Member1, externalData.m_Member2, &externalData.m_String[0]); system("AUSE"); return 0; } |
#include <stdio.h> struct atomic_t { int val ; } ; struct atomic_t GetAtomic() { struct atomic_t a ; a.val = 0x33 ; return a ; } int main() { struct atomic_t b ; b = GetAtomic() ; return b.val>0 ? 1 : 0 ; } 去掉截屏 , 免得flw老大不高兴. |
ret_stru.jpg (291 Bytes, 下载次数: 123)
GetAtomic proc near var_4= dword ptr -4 arg_0= dword ptr 8 push ebp mov ebp, esp sub esp, 10h mov edx, [ebp+arg_0] mov [ebp+var_4], 33h mov eax, [ebp+var_4] mov [edx], eax mov eax, edx leave retn 4 GetAtomic endp |
public main main proc near var_24= dword ptr -24h arg_0= byte ptr 4 lea ecx, [esp+arg_0] and esp, 0FFFFFFF0h push dword ptr [ecx-4] push ebp mov ebp, esp push ecx sub esp, 18h lea eax, [ebp-18h] mov [esp+24h+var_24], eax call GetAtomic sub esp, 4 mov eax, [ebp-18h] mov [ebp-8], eax mov eax, [ebp-8] test eax, eax setnle al movzx eax, al mov ecx, [ebp-4] leave lea esp, [ecx-4] retn main endp |
struct A { int i; }; struct A func() { struct A a; a.i = 0; return a; } |
void func(struct A* p) { struct A a; a.i = 0; *p = a; //拷贝发生在这里 } |
原帖由 w_anthony 于 2010-1-26 23:31 发表
最烦那些一上来就装X的,摆出一付自己高人一等架势的家伙。就算你再牛X,谦虚一点不行么?更何况凡是人,都有出错的可能,给别人点面子,也给自己留条后路。
void func(struct A* p)
{
struct A a;
a.i = 0;
*p = a; //拷贝发生在这里
}
原帖由 w_anthony 于 2010-1-26 23:31 发表
最烦那些一上来就装X的,摆出一付自己高人一等架势的家伙。就算你再牛X,谦虚一点不行么?更何况凡是人,都有出错的可能,给别人点面子,也给自己留条后路。
struct A
{
int i;
};
struct A func()
{
struct A a;
a.i = 0;
return a;
}
编译后基本上相当于(VC编译的)
void func(struct A* p)
{
struct A a;
a.i = 0;
*p = a; //拷贝发生在这里
}
原帖由 OwnWaterloo 于 2010-1-26 23:53 发表
你试过没有, 你确定?
23楼的汇编代码你看没有? 哪一个函数会"写"内存???
上面的有vc6、8、9的汇编输出, 你说的VC又是哪个版本?
再者, 只要有一个反例,就可以证明对结构体的返回并不全是采 ...
原帖由 OwnWaterloo 于 2010-1-26 23:59 发表
"以我的代码"并不能证明什么。
看29楼, 只要能够举出一个没有采用隐式指针参数的反例, 就可以说明这个结论是错误的:
结论是 : 并不都是这样。
上面5份代码, 全都是通过寄存器返回的, 没有写 ...
原帖由 w_anthony 于 2010-1-27 00:09 发表
我想我是得再清楚一点,这里的例子举的不好,struct A太小了,结果就是OwnWaterloo,直接用寄存器了,看不出你所说的“拷贝无法自圆其说论”,改成
struct A
{
int i, j, g;
};
就行了。
void func(struct A* p) { p->i = 0; } |
void func(struct A* p) { struct A a; a.i = 0; *p = a; //拷贝发生在这里 } |
原帖由 OwnWaterloo 于 2010-1-27 00:23 发表
我就缺vc7 …… vc10都有, 只是不常用……
感觉它是一个过度版本, 用户不如vc6广, 对标准支持度又不如vc8以后的版本……
支持谁其实不重要, 就像你说的, 人总是会犯错的。
所以, 我选择支持真理, ...
原帖由 w_anthony 于 2010-1-26 23:31 发表
最烦那些一上来就装X的,摆出一付自己高人一等架势的家伙。就算你再牛X,谦虚一点不行么?更何况凡是人,都有出错的可能,给别人点面子,也给自己留条后路。
struct A
{
int i;
...
C++03 12.8 p211
When certain criteria are met, an implementation is allowed to omit the copy construction of a class object,
even if the copy constructor and/or destructor for the object have side effects. In such cases, the implementation
treats the source and target of the omitted copy operation as simply two different ways of referring to
the same object, and the destruction of that object occurs at the later of the times when the two objects
would have been destroyed without the optimization.111) This elision of copy operations is permitted in the
following circumstances (which may be combined to eliminate multiple copies):
— in a return statement in a function with a class return type, when the expression is the name of a
non-volatile automatic object with the same cv-unqualified type as the function return type, the copy
operation can be omitted by constructing the automatic object directly into the function’s return value
— when a temporary class object that has not been bound to a reference (12.2) would be copied to a class
object with the same cv-unqualified type, the copy operation can be omitted by constructing the temporary
object directly into the target of the omitted copy
[Example:
class Thing {
public:
Thing();
˜Thing();
Thing(const Thing&);
};
Thing f() {
Thing t;
return t;
}
Thing t2 = f();
Here the criteria for elision can be combined to eliminate two calls to the copy constructor of class Thing:
the copying of the local automatic object t into the temporary object for the return value of function f()
and the copying of that temporary object into object t2. Effectively, the construction of the local object t
can be viewed as directly initializing the global object t2, and that object’s destruction will occur at program
exit. —end example]
原帖由 OwnWaterloo 于 2010-1-27 01:35 发表
T /* temporary*/ make_T(p) {
T r; // 一次默认构造
calculate(&r, p); // 在r上计算
return r; // 这里满足条件1, 所以返回值那个临时对象其实是引用这个local r的另一种方式
// r 将直接在temporary 上构造; 而在r上的计算, 也将被替换为在temporary上的计算
}
原帖由 思一克 于 2010-1-27 11:56 发表
//thisfile.c
#include
struct A {
char ch[4*1024];
};
char *stkl, *stkh;
struct A f(int i)
{
int k, *kp;
struct A b;
int tmp;
b.ch[0] = 'a';
printf("b at %p - ...
原帖由 思一克 于 2010-1-27 09:01 发表
结构很小的时候不是真实情况。可以优化为通过寄存器了。
大的结构说明问题。
一般是用一个隐指针参数告诉函数站上的临时结构地址。返回结构的函数完成memcpy.
主函数中有额外的结构赋值(不是调用那个), ...
原帖由 w_anthony 于 2010-1-27 09:17 发表
测试了一下,VC7没遵守这规则,不管开不开优化这里都会有Copy Construct,而MinGW不管开不开优化则都没有Copy Construct。
原帖由 OwnWaterloo 于 2010-1-28 01:36 发表
经常看到类似这样的代码: (可能写错了 大致就这么个意思)
int f(a, b)
int a,
int b
{
...
}
怎么说呢, 当历史车轮前进的同时, 总是有守旧派的![]()
说到 ...
原帖由 OwnWaterloo 于 2010-1-28 00:55 发表
嘿嘿, 换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 eli ...
A func(int param); A a = func(0); doSomething(&a); a = func(1); //软肋 doSomething(&a); |
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;
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).
原帖由 OwnWaterloo 于 2010-1-28 17:22 发表
你看这么理解可行不?
1. 如果功能已经确定, 就是"修改一个已经存在的对象"
那没得说, 肯定是传入该对象的引用或者指针, 而不是返回一个新的值。
比如 replace
2. 如果功能被确定为 "返回一个新对 ...
原帖由 OwnWaterloo 于 2010-1-28 22:22 发表
再换一个角度吧……
比如就是string.replace。 既可以提供返回值的, 也可以提供在一个对象上修改的版本。
(不写模板了, 实际上是个模板)
class string {
public:
string replace( ... );
s ...
欢迎光临 Chinaunix (http://bbs.chinaunix.net/) | Powered by Discuz! X3.2 |