【问题标题】:C11 - convert pointer-to-struct to struct's anonymous first memberC11 - 将指向结构的指针转换为结构的匿名第一个成员
【发布时间】:2015-03-11 16:44:31
【问题描述】:

C 标准规定:

一个指向结构对象的指针,经过适当的转换,指向它的初始成员(或者如果该成员是位域,则指向它所在的单元),反之亦然。

如果所讨论的结构的第一个成员是匿名结构/联合,是否有任何可能(并且定义明确)的方式在 C11 中执行这种“合适的强制转换”?或者如果包含结构是匿名的,则执行“反之亦然”的反向转换?

我猜想,强制转换为具有与匿名结构相同的成员序列的非匿名结构会使其定义不明确,因为它们不兼容,因此不能保证具有相同的内存布局。

但是,C 标准规定:

而且,两种结构, 在单独的翻译单元中声明的联合或枚举类型是兼容的,如果它们的 标签和成员满足以下要求:如果使用标签声明,则 其他应使用相同的标签声明。如果两者都在其范围内的任何地方完成 相应的翻译单位,则适用以下附加要求:应 成员之间是一一对应的<...>

我们可以尝试将此规则应用于匿名结构吗?假设我们有以下设置:

header.h:

struct container {
    struct {
        int a;
        char b;
    };
};

void print(struct container *pcontainer);

sep.c:

#include <stdio.h>
#include "header.h"

void print(struct container *pcontainer){
    printf("%d\n", ((struct { int a; char b; }*)pcontainer)->a);
}

main.c:

#include "header.h"

int main(void){
    struct container container, *pcontainer;

    pcontainer = &container;
    pcontainer->a = 1;

    print(pcontainer);

    return 0;
}

(在 gcc (GCC) 4.8.3 20140911 上编译并输出 1)。

考虑在print 函数内的强制转换中使用的匿名结构作为struct container 的第一个成员的匿名结构main.c 中结束时间>。它们可以被视为“在单独的翻译单元中声明的类型”吗?另外,它们是否真的满足所有其他兼容性要求,还是我误解了什么?

【问题讨论】:

  • 请注意,相同的结构总是具有相同的内存布局(至少对于可以独立编译和链接单独的源文件的实现而言),即使它们不兼容,因为可能存在是在另一个翻译单元中与它们两者兼容的另一个相同结构。这里的问题是是否违反了严格的别名。
  • @mafso:当然,我很清楚这一点。我只是对这种情况下的行为是否被标准明确定义感兴趣。
  • 另外注意,这并不是关于匿名结构,而是关于没有标签的结构。所以这个问题也适用于 C99。
  • 我提到的 [...] 定义不明确,因为它们不兼容,因此不能保证具有相同的内存布局。 一个实现,其中他们没有,会很做作。另一方面,严格别名可能会成为实际代码中实际实现的问题。 (而且我也很好奇这个问题,我没有质疑。)

标签: c pointers struct c11 anonymous-struct


【解决方案1】:

什么是翻译单元:

5.1.1.1 程序结构

  1. C 程序不需要同时翻译。程序的文本被保留 以本国际标准中称为源文件(或预处理文件)的单位。 一个 源文件以及通过预处理包含的所有头文件和源文件 指令#include 被称为预处理翻译单元。预处理后,一个 预处理翻译单元称为翻译单元。

所以c文件加上预处理后的头文件形成一个翻译单元。让我们来看看由 sep.cheader.h 组成的翻译单元。它包含结构struct { int a; char b; } 的两个声明,一个在结构容器中,另一个在函数print 中。这些结构在同一个翻译单元中声明。

6.2.7 兼容类型和复合类型

  1. 如果它们的类型相同,则两种类型具有兼容的类型。用于确定两种类型是否兼容的附加规则在 6.7.2 中描述了类型说明符,在 6.7.3 中描述了类型限定符,在 6.7.6 中描述了声明符。 此外,在单独的翻译中声明了两种结构、联合或枚举类型...

剩余的文本是指在单独的翻译单元中声明的类型。

由于结构没有在单独的翻译单元中声明,它们不属于 6.2.7 规则。

因此,在我的解释中,结构容器中的结构和 print() 中的转换中的结构不兼容。

【讨论】:

  • 是的,但问题是关于 struct container 的问题,它最终出现在 main.c 中。从技术上讲,如果我理解正确,它应该是传递给 print 函数的指针所指向的对象的真实类型。当然,它与sep.c 中声明的struct container 兼容,但这不会使其成为一个单独的问题吗?
  • @Mints97 指针来自哪里并不重要。从 main 调用函数不会改变结构在其他翻译单元中不兼容的事实。
  • @Mints97 不,main 中的 struct container 类型与 sep 中的类型兼容,这就是您传递的内容。但匿名结构不是。 (这是我的解释。有趣的问题。)
  • 感谢您的输入,让我们等待其他人对标准的解释。你没有说服我=P
  • @Mints97:这是一个有趣的反对意见。 sep.h 中的两个结构显然不兼容(如本答案所示),尽管它们似乎都与 main.c 中的结构兼容。我总是发现“兼容类型”关系不是传递性有点不直观,但我从来没有想过这样的例子。
猜你喜欢
  • 2016-04-29
  • 2015-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多