[注意:这是从https://softwareengineering.stackexchange.com/q/369604/126197重新发布的,由于某种原因,这个问题立即被低估了。两次。显然,在这里有更多的爱!]
这里有一些代码从供应商的例子中解释过。
我已经找了关于按值传递堆栈分配结构的权威文档,但是还没找到确定的单词。简而言之:C99是否保证这是安全的?
typedef struct {
int32_t upper;
int32_t lower;
} boundaries_t;
static boundaries_t calibrate() {
boundaries_t boundaries; // struct allocated on stack
boundaries.upper = getUpper();
boundaries.lower = getLower();
return boundaries; // return struct by value
}
int main() {
boundaries_t b;
b = calibrate();
// do stuff with b
...
}
请注意calibrate()
在堆栈上分配boundaries
结构,然后按值返回。
如果编译器可以保证calibrate()
的堆栈帧在分配给b
时完好无损,那么一切都很好。也许这是C99的价值合约中的合同的一部分?
(上下文:我的世界是很少看到pass-by-value的嵌入式系统。我知道从堆栈分配的结构返回一个指针是灾难的一个方法,但是这个传值东西感觉很陌生。)
答案 0 :(得分:7)
是的,它非常安全。按值返回时,它会将结构成员复制到调用者的结构中。只要结构不包含任何指向本地对象的指针,它就是有效的。
返回结构往往不常见,因为如果它们变大,则需要大量复制。但有时我们将数组放入结构中以允许它们通过值传递和返回(数组通常在用作参数时返回指针或返回值),就像其他数据类型一样。
(我相信@Barmar不会介意......)
正如@DanielH指出的那样,在SysV ABI for amd64的情况下,编译器将提供按值返回结构的规定。如果它很小,整个结构可以在寄存器中返回(读取:快速)。如果它更大,编译器在调用者的堆栈帧中分配空间并将指针传递给被调用者。然后被调用者在返回时将结构的值复制到该结构中。来自doc:
如果类型具有类MEMORY,则调用者为该类提供空间 返回值并在%rdi中传递此存储的地址,就像它一样 是该函数的第一个参数。实际上,这个地址 成为“隐藏的”第一个论点。
答案 1 :(得分:1)
b = calibrate();
// do stuff with b
表现得很好。
boundaries_t
仅包含作为成员的整数类型。按值传递并使用在函数调用中分配给它的对象是完全安全的。
答案 2 :(得分:0)