在匿名联盟

时间:2015-11-04 23:08:53

标签: c gcc c99 language-design c11

首先,类型检查并不是我正在寻找的正确术语,所以我将解释: 假设我想使用匿名联合,我在struct const中创建了union声明,因此在初始化之后,值不会改变。这应该允许静态检查是否正在访问联合的未初始化成员。在下面的示例中,为a(int)或b(float)初始化实例。在初始化之后,我希望无法访问其他成员:

struct Test{
    const union{
        const int a;
        const float b;
    };
};

int main(){
    struct Test intContainer = { .a=5 };
    struct Test floatContainer = { .b=3.0 };

    int validInt = intContainer.a;
    int validFloat = floatContainer.b;

    // For these, it could be statically determined that these values are not in use (therefore invalid access)
    int invalidInt = floatContainer.a;
    float invalidFloat =  intContainer.b;

    return 0;
}

我希望最后两个作业能够给出错误(或者至少是一个警告),但是它没有给出(使用gcc 4.9.2)。 C是否设计为不检查这个,还是它实际上是语言/编译器的缺点?或者想要使用这种模式只是愚蠢吗?

在我看来,如果这是一个功能,它看起来有很大的潜力,所以有人可以向我解释为什么我不能用它来区分两个"子类型& #34;一个相同的结构(每个联合值一个)。 (可能有任何建议我仍然可以做这样的事情吗?)

编辑: 显然它不符合语言标准,编译器也不会检查它。我个人认为这是一个很好的功能,因为它只是消除了使用标记的联合手动检查union的内容。所以我想知道,有没有人知道它为什么没有语言特色(或者它的编译器)?

1 个答案:

答案 0 :(得分:1)

  

我希望最后两个作业能够给出错误(或者至少是一个警告),但是它没有给出(使用gcc 4.9.2)。 C是否设计为不检查这个,还是它实际上是语言/编译器的缺点?

这是编译器的正确行为。

float invalidInt = floatContainer.a;
float invalidFloat = intContainer.b;

在第一个声明中,您正在初始化具有float值的int对象,而在第二个声明中,您正在初始化具有float值的float对象。在C中,您可以将任何算术类型分配(或初始化)到任何算术类型,而无需任何强制转换。所以不需要诊断。

在您的特定情况下,您还阅读的union成员与上次用于存储其值的union成员的成员不同。假设union成员具有相同的大小(例如,此处为floatint),则这是指定的行为,不需要诊断。如果union成员的大小不同,则行为未指定(但仍然不需要诊断)。