了解对象表示

时间:2019-03-08 14:50:09

标签: c struct language-lawyer

问题: :如果我们有两个不兼容的结构或联合体,但两种类型的对象的都相同如果我采用一种类型的某个对象的对象表示形式并将其“重新解释”为另一种类型,则对象表示形式的大小会得到未定义/未指定/完全定义的行为。 (我希望措辞不会很奇怪)。

我的想法:

我之所以提到了结构或联合,是因为N6.2.6.1(p6)

  

结构或联合对象的值永远不会是陷阱

我还发现我们可以将对象的值复制到char数组6.2.6.1(p4)中:

  

可以将值复制到unsigned char [n]类型的对象中   (例如,通过memcpy);所得的字节集称为对象   值的表示形式。

但是标准未指定我们可以复制对象表示形式。因此,我认为将对象表示形式复制回具有相同大小表示形式的对象是UB,即使它不是陷阱,但我不确定...

示例:

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
    }
}

可以在struct test1_t之后的int a;中使用填充来解释结果。

1 个答案:

答案 0 :(得分:2)

  

如果我们有两个不兼容的结构或联合,但对象是   这两种类型的对象表示形式的大小都相同   如果我拿了对象,则会得到未定义/未指定/完全定义的行为   一种类型的某个对象的表示形式并“重新解释”它   作为另一种类型。

问题Can memcpy be used for type punning?,尤其是问题EOF's answer包含相当多的相关信息和讨论,尽管它们关注的是不同的细节。特别是

  • memcpy()本身很好,只要这两种类型确实具有相同的大小(在您的示例代码中似乎不太可能),并且
  • 从那里开始,部分取决于接收对象是否具有声明的类型。
    • 如果不是,则随后通过与源对象的有效类型不同的左值访问它,从而产生UB。
    • 如果确实如此(如您的示例所示),则可以访问结构本身,因为您观察到,结构类型没有陷阱表示。

但是,在结构和联合的情况下,我们还必须考虑成员。它们的类型可以提供陷阱表示形式,如果可以,则memcpy()可能导致一个或多个成员包含这种表示形式。读取当前包含陷阱表示形式的成员的值将生成UB。

此外,即使假设示例中的两种结构类型具有相同的大小,也未指定其布局的相关细节。特别是,在您的示例代码中,如果两者(1)两种结构都具有相同的大小,并且(2)第二个printf调用将打印代码注释所建议的结果,将令人惊讶。 (在更正格式以正确匹配数据之后;由于格式和变量之间的不匹配,目前printf具有UB。)

总的来说,您的示例代码并不严格符合。其行为的各个方面均未指定,并且有可能但不确定地表现出未定义的行为。