在 C 中向上转型和向下转型继承的结构
Upcasting and downcasting inherited structures in C
我想知道所提供的示例在 C:
中是否安全(无 UB)
typedef struct {
uint32_t a;
} parent_t;
typedef struct {
parent_t parent;
uint32_t b;
} child_t;
typedef struct {
uint32_t x;
} unrelated_t;
void test_function(parent_t* pParent) {
((child_t*)pParent)->b = 5U; // downcast is valid only if relation chain is valid
}
int main()
{
child_t child;
unrelated_t ub;
test_function((parent_t*)&child); // valid upcast?
test_function((parent_t*)&ub); // probably UB?
return 0;
}
由于显式强制转换,没有保证和良好的类型检查,但只要传递了正确的参数,这应该可以正常工作吗?
铸造的规则是https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p7:
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined.
还有结构 https://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p15 :
A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa.
然后访问 https://port70.net/~nsz/c/c11/n1570.html#6.5p7 :
An object shall have its stored value accessed only by an lvalue
expression that has one of the following types:88)
- a type compatible with the effective type of the object,
- a qualified version of a type compatible with the effective type of the object,
- a type that is the signed or unsigned type corresponding to the effective type of the object,
- a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
- an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a
member of a subaggregate or contained union), or
- a character type.
as long as proper parameters are passed this should work right?
“应该工作”和“保证工作”之间存在着巨大的海洋。目标是编写保证按预期工作的代码——它没有未定义的行为,因为无法保证未定义时会发生什么。
test_function((parent_t*)&child); // valid upcast?
是的,这是定义的行为。 &child
指向 &child.parent
,因此结果指针必须正确对齐 parent_t
。
那么(child_t*)pParent
也是有效的,因为它指向一个child_t
对象。
然后访问它((child_t*)pParent)->
也是有效的,因为有一个child_t
访问的对象与它是相同类型child_t
,所以它肯定是兼容类型。
test_function((parent_t*)&ub); // probably UB?
很可能,将指针从unrelated_t*
转换为parent_t*
完全没问题——很可能alingof(unrelated_t)
等于alingof(parent_t)
,因为里面只有uint32_t
。但是,这取决于。当 (parent_t*)&ub
的结果指针未正确对齐到 parent_t
.
时,它可能无效
之后,(child_t*)pParent
的类似故事在 test_function
中具有相同的指针值。请注意,child_t
可能比 parent_t
有更严格的对齐要求,因此虽然前面的转换可能有效,但这个可能不是,以相同的方式——取决于所涉及类型的对齐要求。
Then 在那之后,使用 ((child_t*)pParent)->
访问 值是未定义的行为。通过 child_t *
句柄访问指向 unrelated_t
对象的指针是未定义的行为。 child_t
与 unrelated_t
不兼容。
我想知道所提供的示例在 C:
中是否安全(无 UB)typedef struct {
uint32_t a;
} parent_t;
typedef struct {
parent_t parent;
uint32_t b;
} child_t;
typedef struct {
uint32_t x;
} unrelated_t;
void test_function(parent_t* pParent) {
((child_t*)pParent)->b = 5U; // downcast is valid only if relation chain is valid
}
int main()
{
child_t child;
unrelated_t ub;
test_function((parent_t*)&child); // valid upcast?
test_function((parent_t*)&ub); // probably UB?
return 0;
}
由于显式强制转换,没有保证和良好的类型检查,但只要传递了正确的参数,这应该可以正常工作吗?
铸造的规则是https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p7:
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined.
还有结构 https://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p15 :
A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa.
然后访问 https://port70.net/~nsz/c/c11/n1570.html#6.5p7 :
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:88)
- a type compatible with the effective type of the object,
- a qualified version of a type compatible with the effective type of the object,
- a type that is the signed or unsigned type corresponding to the effective type of the object,
- a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
- an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
- a character type.
as long as proper parameters are passed this should work right?
“应该工作”和“保证工作”之间存在着巨大的海洋。目标是编写保证按预期工作的代码——它没有未定义的行为,因为无法保证未定义时会发生什么。
test_function((parent_t*)&child); // valid upcast?
是的,这是定义的行为。 &child
指向 &child.parent
,因此结果指针必须正确对齐 parent_t
。
那么(child_t*)pParent
也是有效的,因为它指向一个child_t
对象。
然后访问它((child_t*)pParent)->
也是有效的,因为有一个child_t
访问的对象与它是相同类型child_t
,所以它肯定是兼容类型。
test_function((parent_t*)&ub); // probably UB?
很可能,将指针从unrelated_t*
转换为parent_t*
完全没问题——很可能alingof(unrelated_t)
等于alingof(parent_t)
,因为里面只有uint32_t
。但是,这取决于。当 (parent_t*)&ub
的结果指针未正确对齐到 parent_t
.
之后,(child_t*)pParent
的类似故事在 test_function
中具有相同的指针值。请注意,child_t
可能比 parent_t
有更严格的对齐要求,因此虽然前面的转换可能有效,但这个可能不是,以相同的方式——取决于所涉及类型的对齐要求。
Then 在那之后,使用 ((child_t*)pParent)->
访问 值是未定义的行为。通过 child_t *
句柄访问指向 unrelated_t
对象的指针是未定义的行为。 child_t
与 unrelated_t
不兼容。