有效类型的已分配对象和结构

时间:2019-01-30 18:05:34

标签: c struct malloc language-lawyer c99

根据c99的规范,我不太了解下面分配的对象的有效类型是怎么回事。

typedef struct {
    int x;
    char y;
} MyStruct ;

MyStruct *make_struct (void) {
    MyStruct *p = malloc(sizeof(MyStruct));
    p->x = 1;
    p->y = 2;

    /* what is the effective type of the allocated object at this point? */

    return p;
}

为分配的对象分配值时,分配的对象的有效类型变为用于存储的左值的类型,但是这里使用的左值是什么?

据我对6.5.2.3p4的了解...

  

后缀表达式,后跟->运算符和标识符,指定结构或联合对象的成员。该值是第一个表达式指向的对象的命名成员的值,并且是一个左值。如果第一个表达式是指向限定类型​​的指针,则结果具有指定成员类型的限定版本。

...“ x-> y”表达式的类型是y的类型(但仅当x指向限定类型​​时才可用)。
那么,我有一个没有有效类型的分配对象和两个具有int和char类型的“内部对象”吗?

多么令人困惑。

编辑: 假设* p的有效类型以int结尾。那么这是未定义的行为吗?最终有人将通过类型为MyStruct的左值访问对象。访问成员是否也暗示访问聚合类型? 这一直在给。

3 个答案:

答案 0 :(得分:3)

在分配的块不具有有效的类型,因为(1)它没有声明的类型,和(2)它没有被分配。该块的部分对应于成员xy具有有效的类型,而不是整个块。

不具有有效类型并不构成未定义的行为,但:每个成员MyStructmake_struct已被赋予了适当的有效类型的单独,返回所以代码访问的成员返回{{ 1}}仍然有效。

可以将您的代码片段修改为使用compound literal初始化整个struct,而不是初始化其组件。这将使有效类型的所分配块的MyStruct

MyStruct

注意:此问题的答案在更新问题后经过了重大编辑。

答案 1 :(得分:3)

行情是从C99 6.5 / 6

  
    

用于访问其存储值的对象的有效类型是对象的声明类型(如果有)。

  
  • malloc(sizeof(MyStruct));此时,返回的数据不具有有效的类型。
  • MyStruct *p = malloc(sizeof(MyStruct));仍然没有有效的类型,p只是指向数据而没有存储任何内容。
  • p->x = 1;的有效类型的规则:

      

    如果将值存储在没有声明类型的对象中,则通过   具有非字符类型的左值,则左值的类型成为该访问和不修改存储值的后续访问的对象的有效类型。

    由于我们有int x;表达式的左值p->x = 1;int,并且变得有效类型的存储的内容在p->x

  • 对于p->y,用于对象访问的左值是字符类型,因此上述规则不适用。也不会将其复制为字符数组。我们在规则的最后一句话结束:

      

    对于没有声明类型的对象的所有其他访问,该对象的有效类型就是用于访问的左值的类型。

    有效的p->y类型变为char,因为表达式p->y = 2;的左值为char

6.5.2.3/4没有关联这里,除了 “...并且是一个左值”。

*p没有这样的有效类型,因为我们从未通过完整的结构类型访问存储区。但是,由于严格的别名规则允许结构访问对象,因此假设{} {1}}这样的表达式仍然定义良好,因为该结构包含与有效类型兼容的成员。在这种情况下,该结构包含MyStruct m = *make_struct();int成员,这些成员与通过charp->x引用的数据最终所具有的有效类型完全兼容。

答案 2 :(得分:0)

在C11草案(N1570)中,除6.5p6(“有效类型规则”)外,处所使用的术语“对象”是指与某个特定类型相关联的存储区域。如果int *p是有效的非null指针,它将指向类型int的对象“指向”或“刚刚过去”。似乎6.5p6使用术语“对象”来指代某种可能实际上可能不是对象的存储区域,但标准的其余部分并未以这种方式使用术语“对象”。除其他事项外,malloc的规范不是说它们返回指向对象的指针,也不创建对象,而是返回指向存储区域的指针。大得足以容纳给定大小的物体。

由于6.5p6使用术语“对象”的方式与在其他地方使用的方式相反,因此其含义将取决于选择该术语的方式。在没有脚注87(“分配的对象没有声明的类型。”)的情况下,可以通过简单地观察每个对象的有效类型就是其类型来解决此问题。如果一个存储区域承认所有可能适合的对象的叠加,但是实际上解释得很好,但是解释了6.5p7的脚注88(“此列表的目的是指定对象可能会或可能会遇到的情况)。 ”,就是说该规则适用的唯一“对象”是那些在与左值相同的上下文中使用的对象,而没有在该左值的派生中被新鲜且明显地使用过。

然而,脚注87清楚地表明6.5p6必须使用与标准中其他所有内容不同的“对象”含义,而无需弄清楚该含义是什么。我认为不可能制定出能够合理处理所有极端情况的定义,而且对于6.5p6或6.5p7的目的是什么还是不是“对象”,标准的作者是否具有共识的含义似乎令人怀疑。 。因此,6.5p6和6.5p7的含义以及基于它们的允许范围将在很大程度上取决于读者如何选择使“对象”的含义成为现实。