函数 return 和赋值之间的语义差异
Semantic difference between function return and assignment
标准在 6.8.6.4 中提供了示例:
EXAMPLE In:
struct s { double i; } f(void);
union {
struct {
int f1;
struct s f2;
} u1;
struct {
struct s f3;
int f4;
} u2;
} g;
struct s f(void)
{
return g.u1.f2;
}
/* ... */
g.u2.f3 = f();
there is no undefined behavior, although there would be if the
assignment were done directly (without using a function call to fetch
the value).
能否解释一下为什么直接赋值会有UB。这似乎与标准示例上方的定义相矛盾:
If the expression has a type different from the return type of the
function in which it appears, the value is converted as if by
assignment to an object having the return type of the function.
所以return
和赋值的语义应该是一样的。
这里的重点不是转换。在例子中,return语句中的值与函数return的类型相同,所以不需要转换。
关键点是要求(标准条款 6.5.16.1,第 3 段)如果重叠是准确的,则分配仅为重叠对象定义:
If the value being stored in an object is read from another object that overlaps in any way
the storage of the first object, then the overlap shall be exact and the two objects shall
have qualified or unqualified versions of a compatible type; otherwise, the behavior is
undefined.
因此作业:
g.u2.f3 = g.u1.f2;
将是未定义的行为(因为对象“不完全重叠”),但在示例中,赋值是通过函数调用发生的,因此赋值不是直接在不完全重叠的对象之间进行的,因此不是未定义的行为.
标准在 6.8.6.4 中提供了示例:
EXAMPLE In:
struct s { double i; } f(void); union { struct { int f1; struct s f2; } u1; struct { struct s f3; int f4; } u2; } g; struct s f(void) { return g.u1.f2; } /* ... */ g.u2.f3 = f();
there is no undefined behavior, although there would be if the assignment were done directly (without using a function call to fetch the value).
能否解释一下为什么直接赋值会有UB。这似乎与标准示例上方的定义相矛盾:
If the expression has a type different from the return type of the function in which it appears, the value is converted as if by assignment to an object having the return type of the function.
所以return
和赋值的语义应该是一样的。
这里的重点不是转换。在例子中,return语句中的值与函数return的类型相同,所以不需要转换。
关键点是要求(标准条款 6.5.16.1,第 3 段)如果重叠是准确的,则分配仅为重叠对象定义:
If the value being stored in an object is read from another object that overlaps in any way the storage of the first object, then the overlap shall be exact and the two objects shall have qualified or unqualified versions of a compatible type; otherwise, the behavior is undefined.
因此作业:
g.u2.f3 = g.u1.f2;
将是未定义的行为(因为对象“不完全重叠”),但在示例中,赋值是通过函数调用发生的,因此赋值不是直接在不完全重叠的对象之间进行的,因此不是未定义的行为.