按值 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的回应。
[注意:这是从 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的回应。