C 理解对象表示
问题:如果我们有两个不兼容的结构或并集,但这两种类型的对象具有相同大小的对象表示,如果我将其中一种类型的某个对象的对象表示形式作为另一种类型“重新解释”,我会得到未定义/未指定/定义良好的行为吗。(我真的希望措辞不奇怪) 我的想法: 我提到结构或联合是因为C 理解对象表示,c,struct,language-lawyer,C,Struct,Language Lawyer,问题:如果我们有两个不兼容的结构或并集,但这两种类型的对象具有相同大小的对象表示,如果我将其中一种类型的某个对象的对象表示形式作为另一种类型“重新解释”,我会得到未定义/未指定/定义良好的行为吗。(我真的希望措辞不奇怪) 我的想法: 我提到结构或联合是因为N6.2.6.1(p6): 结构或联合对象的值决不是陷阱 我还发现,我们可以将对象的值复制到char数组6.2.6.1(p4): 该值可以复制到类型为无符号字符[n] (例如,通过memcpy);产生的字节集称为对象 值的表示 但是标准没有规定
N6.2.6.1(p6)
:
结构或联合对象的值决不是陷阱
我还发现,我们可以将对象的值复制到char数组6.2.6.1(p4)
:
该值可以复制到类型为无符号字符[n]
(例如,通过memcpy
);产生的字节集称为对象
值的表示
但是标准没有规定我们可以将对象表示复制回去。因此,我认为将对象表示复制回具有相同大小表示的类型的对象(即使它不是陷阱)是非常必要的,但我不确定
示例:
结果可以用struct test1\u t
中int a之后的填充来解释代码>
如果我们有两个不兼容的结构或并集,但是
这两种类型的对象表示大小相同
如果获取对象,则获取未定义/未指定/定义良好的行为
表示其中一种类型的某些对象并“重新解释”它
作为另一种类型
这个问题,特别是它包含了大量的相关信息和讨论,尽管它们侧重于不同的细节。特别是,
memcpy()
本身就可以了,只要这两种类型的大小确实相同(在示例代码中似乎不太可能),并且
- 因此,这部分取决于接收对象是否具有声明的类型。
- 如果没有,则随后通过与源对象的有效类型不同的类型的左值访问它会生成UB
- 如果确实如此(如示例中所示),那么访问结构本身是可以的,因为正如您所观察到的,结构类型没有陷阱表示
然而,在结构和工会的情况下,我们也必须考虑成员。它们的类型可能提供陷阱表示,如果提供,则memcpy()
可能会导致一个或多个成员包含此类表示。读取当前包含陷阱表示的成员的值将生成UB
此外,即使假设示例中的两种结构类型具有相同的大小,它们的布局的相关细节也未指定。特别是,在您的示例代码中,如果两者都(1)两个结构的大小相同,(2)第二个printf
调用打印代码注释所建议的结果,这将是令人惊讶的。(更正格式以正确匹配数据后;由于格式和变量之间不匹配,目前printf
具有UB。)
因此,总体而言,您的示例代码并不严格符合要求。其行为的各个方面尚未明确,它可能(但不确定)表现出未定义的行为。这在示例代码中似乎不太可能,但它们确实存在。我检查了它们的sizeof
输出。在我的机器上等于16。我猜填充发生在struct test1_t::a
@EOF中,正如参考答案中提到的,我们可以使用memcpy
进行类型双关,在我的例子中,行为是定义良好的,因为t1
声明了类型struct test1_t
,这也是一种有效类型。
struct test1_t{
int a;
long b;
};
struct test2_t{
int c;
int d;
int e;
int f;
};
int main(){
struct test1_t t1 = {.a = 100, .b = 2000};
struct test2_t t2 = {.c = 1000, .d = 20000, .e = 300000, .f = 4000000};
size_t size;
if((size = sizeof(struct test1_t)) == sizeof(struct test2_t)){
char repr[size];
memcpy(&repr, &t2, size); // since value of structure or union
// is never a trap why don't we treat
// the representation as of some object
// of type struct test_t1
memcpy(&t1, &repr, size);
printf("t1.a = %d\n", t1.a); //t1.a = 1000
printf("t1.b = %d\n", t1.b); //t1.b = 300000
}
}