按值 return 堆栈分配结构安全吗?

Is it safe to return a stack-allocated structure by value?

[注意:这是从 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 结构,然后按值 returns 它。

如果编译器可以保证 calibrate() 的栈帧在赋值给 b 时是完整的,那么一切都很好。也许这是 C99 按值传递中约定的一部分?

(上下文:我的世界是很少见按值传递的嵌入式系统。我知道从堆栈分配的结构返回指针是灾难的根源,但是这个传递- 按价值的东西感觉很陌生。)

是的,绝对安全。当您按值 return 时,它会将结构的成员复制到调用者的结构中。只要该结构不包含任何指向本地对象的指针,它就是有效的。

返回结构往往不常见,因为如果它们很大,则需要进行大量复制。但有时我们将数组放入结构中,以允许它们像其他数据类型一样按值传递和 returned(当用作参数或 return 值时,数组通常会退化为指针)。

原始提问者的附录

(我相信@Barmar 不会介意...)

正如@DanielH 指出的那样,在SysV ABI for amd64 的情况下,编译器将对return 结构按值进行规定。如果它很小,整个结构可以 returned 在寄存器中(读取:快速)。如果它更大,编译器会在调用者的堆栈帧中分配空间并将指针传递给被调用者。然后,被调用者将结构的值复制到 return 上的那个结构中。来自文档:

If the type has class MEMORY, then the caller provides space for the return value and passes the address of this storage in %rdi as if it were the first argument to the function. In effect, this address becomes a “hidden” first argument.

b = calibrate();
// do stuff with b

行为端正。

boundaries_t 仅包含整数类型作为成员。按值传递它并在函数调用中使用它分配给它的对象是完全安全的。

我没有 link C99 参考,但引起我注意的是结构赋值。

Assign one struct to another in C

基本上是Barmar的回应。