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

Effective types of allocated objects and structs

根据 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..​​.

A postfix expression followed by the -> operator and an identifier designates a member of a structure or union object. The value is that of the named member of the object to which the first expression points, and is an lvalue. If the first expression is a pointer to a qualified type, the result has the so-qualified version of the type of the designated member.

..."x->y" 表达式的类型是 y 的类型(但前提是 x 指向限定类型​​)。
那么我有一个没有有效类型的分配对象和两个 "inner objects" 类型为 int 和 char?

多么混乱..

编辑: 假设 *p 的有效类型最终为 int。那么这是未定义的行为吗?有人最终会通过类型为 MyStruct 的左值访问该对象。访问成员是否也意味着访问聚合类型? 这一直在给予..

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

没有有效类型并不构成未定义的行为,但是:从 make_struct 返回的 MyStruct 的每个成员都被单独赋予了适当的有效类型,因此访问返回成员的代码struct 仍然有效。

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

MyStruct *make_struct () {
    MyStruct *p = malloc(sizeof(MyStruct));
    *p = (MyStruct){.x = 1, .y = 2};
    return p;
}

注意:此答案在问题更新后进行了大量编辑。

引用自 C99 6.5/6

The effective type of an object for an access to its stored value is the declared type of the object, if any.

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

    If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value.

    因为我们有 int x; 表达式 p->x = 1; 的左值是 int 并且它成为存储在 p->x.

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

    For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access.

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

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

*p 本身没有有效类型,因为我们从未通过完整的结构类型访问内存区域。然而,像 MyStruct m = *make_struct(); 这样的表达式仍然是明确定义的,因为严格的别名规则允许结构访问对象,前提是该结构包含与有效类型兼容的成员。在这种情况下,该结构包含 intchar 成员,它们与数据通过 p->xp->y 最终引用的有效类型完全兼容。

除了 6.5p6("Effective Type Rule")外,C11 草案 (N1570) 中的所有地方都使用术语 "object",指的是与某种特定类型相关联的存储区域。如果 int *p 是一个有效的非空指针,它将指向 "to" 或 "just past",类型为 int 的对象。似乎 6.5p6 使用术语 "object" 来指代某种存储区域,它实际上可能是对象,也可能不是对象,但标准的其余部分不使用术语 "object"一种时尚。除其他事项外,malloc 的规范确实 而不是 说它 returns 是一个指向对象的指针,也不是说它创建了一个对象,而是说它 returns 指向足以容纳给定大小的对象的存储区域的指针。

因为 6.5p6 使用术语 "object" 的方式与其在其他地方的用法相反,其含义将取决于人们选择如何定义该术语。在没有脚注 87 ("Allocated objects have no declared type.") 的情况下,可以通过简单地观察每个对象的有效类型就是它的类型来解决这个问题。如果一个人将存储区域识别为可以容纳其中的所有对象的叠加,但将 6.5p7 ("The intent of this list is to specify those circumstances in which an object may or may not be aliased.") 的脚注 88 解释为表示唯一 "objects"适用的规则是那些在与左值相同的上下文中使用而没有在该左值的推导中被新鲜和明显地使用的那些。

然而,脚注 87 明确指出 6.5p6 必须使用与标准中其他所有内容不同的 "object" 含义,但没有明确说明该含义是什么。我认为不可能制定一个合理地处理所有极端情况的定义,而且对于 6.5p6 或6.5p7。因此,6.5p6 和 6.5p7 的含义,以及基于它们的允许范围,将在很大程度上取决于 reader 如何选择避开 "object".

的含义