将“`unsigned` bitset”转换为“unsigned”时出现 gcc 警告;现在还安全吗?

gcc warning when casting "`unsigned` bitset" to `unsigned`; is it still safe?

出于调试目的,我确实将“unsigned bitset”类型转换为 unsigned:

unsigned 位集”如下所示:

typedef struct {
        unsigned f1 : 1;
        unsigned f2 : 1;
        unsigned f3 : 1;
/* ...less than 10 alltogether... */
} output_flags_t

输出代码如下所示:

output_flags_t output_flags;
/*...*/
printf("... %u\n", *(const unsigned *) &output_flags);

gcc 不喜欢直接转换)

然而,当使用 -O2 时,我收到一个额外的警告(gcc 4.8.5):

warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

我想知道: 如果“unsigned bitset”和unsigned的位数相同;警告不应该毫无意义吗? 那是: 只有当两种类型的尺寸不同时,该警告才有意义吗?

是否有更简洁的方法来打印“unsigned 位集”的值?

使用 union:

可能更干净
typedef union {
    struct {
        unsigned f1 : 1;
        unsigned f2 : 1;
        unsigned f3 : 1;
        /* ...less than 10 altogether... */
    };
    unsigned all;
} output_flags_t;

(注意:未命名的 struct/union 成员是在 C11 中添加的,尽管一些编译器在标准化之前支持它们。)

输出代码如下:

output_flags_t output_flags = {0};
output_flags.f3 = 1;
printf("... %u\n", output_flags.all);

在我的系统上,以上打印:

... 4

但输出取决于实现,output_flags.all 的值可能是陷阱表示(见下文)。

关于使用 union 进行类型双关,这在 C 标准中是明确允许的,尽管被双关的值可能是陷阱表示:

C17 6.5.2.3

  1. 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, 97) and is an lvalue if the first expression is an lvalue. If the first expression has qualified type, the result has the so-qualified version of the type of the designated member.

97) If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called “type punning”). This might be a trap representation.

不是。改为使用联合:


typedef union {
    struct {
        unsigned f1 : 1;
        unsigned f2 : 1;
        unsigned f3 : 1;
/* ...less than 10 alltogether... */
    }
    unsigned raw;
} output_flags_t;