C: 是否使用转换为 "outer"结构类型的指针访问嵌套结构的初始成员?

标签 c pointers struct types strict-aliasing

<分区>

我正在尝试理解用于 C 别名分析的所谓“公共(public)初始序列”规则。这个问题不涉及 C++。

具体根据资源(例如CPython PEP 3123 ),

[A] value of a struct type may also be accessed through a pointer to the first field. E.g. if a struct starts with an int, the struct * may also be cast to an int *, allowing to write int values into the first field.

(强调我的)。

我的问题可以大致表述为“是否能够通过指向第一个成员类型的指针访问结构来穿透嵌套结构?”也就是说,如果访问是通过指针指向的类型(假设类型 struct A)与第一个成员的类型(假设类型 )不完全相同,会发生什么情况struct B),但是指向的类型 (struct A) 与 struct B 和“底层”访问具有共同的第一个初始序列只对那个共同的初始序列做

(我主要对结构感兴趣,但我可以想象这个问题也可能与 union 体有关,尽管我认为 union 体有它们自己的棘手部分 w.r.t. 别名。)

这个措辞可能不太清楚,所以我尝试用如下代码来说明我的意图(也可在 godbolt.org 获得,而且代码似乎编译得很好,达到了预期的效果):

/* Base object as first member of extension types. */
struct base {
    unsigned int flags;
};

/* Types extending the "base" by including it as first member */
struct file_object {
    struct base attr;
    int index;
    unsigned int size;
};

struct socket_object {
    struct base attr;
    int id;
    int type;
    int status;
};

/* Another base-type with an additional member, but the first member is
 * compatible with that of "struct base" */
struct extended_base {
    unsigned int flags;
    unsigned int mode;
};

/* A type that derives from extended_base */
struct extended_socket_object {
    struct extended_base e_attr;  /* Using "extended" base here */
    int e_id;
    int e_type;
    int e_status;
    int some_other_field;
};

/* Function intended for structs "deriving from struct base" */
unsigned int set_flag(struct base *objattr, unsigned int flag)
{
    objattr->flags |= flag;
    return objattr->flags;
}

extern struct file_object *file;
extern struct socket_object *sock;
extern struct extended_socket_object *esock;

void access_files(void)
{
    /* Cast to pointer-to-first-member-type and use it */
    set_flag((struct base *)file, 1);

    set_flag((struct base *)sock, 1);

    /* Question: is the following access defined?
     * Notice that it's cast to (struct base *), rather than 
     * (struct extended_base *), although the two structs share the same common
     * initial member and it is this member that's actually accessed. */
    set_flag((struct base *)esock, 1);
    return;
}

最佳答案

这是安全的,因为您正试图访问类型为 struct extended_base 的对象,就好像它是类型为 struct base 的对象一样>.

但是,有些规则允许通过 union 访问两个结构的初始公共(public)序列。来自 C standard 的第 6.5.2.3p6 节:

One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members

因此,如果您将 struct extended_socket_object 的定义更改为:

struct extended_socket_object {
    union u_base {
        struct base b_attr;
        struct extended_base e_attr;
    };
    int e_id;
    int e_type;
    int e_status;
    int some_other_field;
};

然后 struct extended_socket_object * 可以转换为 union u_base *,后者又可以转换为 struct base *。根据第 6.7.2.1 p15 和 p16 节,这是允许的:

15 Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. 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. There may be unnamed padding within a structure object, but not at its beginning.

16 The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit-field, then to the unit in which it resides), and vice versa.

然后允许访问 b_attr->flags,因为它位于 6.5.2.3p6 中的 union 。

关于C: 是否使用转换为 "outer"结构类型的指针访问嵌套结构的初始成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66806198/

相关文章:

c - 我在这个 C 程序中检查字符串是否是回文时做错了什么?

c++ - 在 C++ 中,结构上的 "new/delete"代替 "malloc/free"有多好?

c - 如何在c中将csv文件读入结构链表

c - 在 Unix 中编程 : Sharing libraries with libraries

c - 在 C 中将字符串转换为 long long 时出现问题

c - C代码每次读取一定数量的文件后退出

c++ - "could not convert template argument"指针参数错误,即使使用强制转换

pointers - 在指针接收器方法中更新值,但值不更新

c++ - 在另一个结构中使用对结构的引用时Arduino编译错误

C - 创建一个匿名结构实例