【问题标题】:Bit-fields of type other than int?非 int 类型的位域?
【发布时间】:2010-02-17 12:24:57
【问题描述】:

我有一个使用如下声明的位域的代码

typedef struct my{
    const char *name;
    uint8_t is_alpha : 1;   
    uint8_t is_hwaccel : 1; 
    uint8_t x_chroma_shift; 
    uint8_t y_chroma_shift; 

} mystr; 

uint8_t 的类型定义为unsigned char

使用此位字段在 MS-VS 2008 中构建代码会给出如下警告:

imgconvert.c(60) : 警告 C4214: 使用了非标准扩展 : 位域类型不是 int。
  1. 在使用非 int 类型的位字段时是否存在任何问题/潜在问题?为什么会出现警告?
  2. C99 C 语言规范是否允许除了 int 类型的位字段?

【问题讨论】:

  • 警告非常不言自明:使用了非标准扩展;您的代码可能存在可移植性问题。
  • @Mehrad:仅当所有目标/编译器具有相同大小的整数时,使用类型 int 从可移植性方面才有用。
  • 你在这里写的是位域,它们的大小在代码中指定。
  • 问题不在于bitfield的大小(是指定的)而是最大bitfield的大小(不大于type)或者padding(两个1位被打包成8bit int和6未使用的位,对于一个 int 它将是 2 个已使用和 30 个空闲)。
  • 另一个你可能感兴趣的话题:stackoverflow.com/questions/54719855/…

标签: c visual-c++ bit-fields


【解决方案1】:

1] 使用非 int 类型的位字段是否存在任何问题/潜在问题?为什么会出现警告?

由于位域是低级的,如果您使用非标准类型,可能会出现可移植性问题。因此警告 - 注意它仍然是警告而不是错误。

2] C99 C 语言规范是否允许除了 int 类型的位字段?

来自 C99 草案:

6.7.2.1 结构和联合说明符

4 位域的类型应为 合格或不合格的版本 _Bool、signed int、unsigned int 或其他一些实现定义的 输入。

【讨论】:

  • “其他实现定义的类型”在标准文档中不是非常无用吗?
  • @Neil Butterworth:ATM,我只有草稿。不过还是需要查一下实际情况。但是,是的,我想你是对的。
  • @dirkgently:仅当所有目标/编译器都保证具有相同大小的整数时,从可移植性方面使用类型 int 才有用。这是一个合理的假设。我不知道这就是我问的原因。
  • @goldenmean:不,标准保证只有char 在所有机器上具有相同的大小。 int 的大小仅定义为一个范围,因此从可移植性的角度来看它不是很有用。为此,将 stdint 标头添加到 C99。我想你应该可以接受这个警告。
  • @dirkgently,sizeof(char) 是一个,但这并不意味着 CHAR_BIT 在所有平台上都是相同的。
【解决方案2】:

为什么不使用int?位域的实际实现因编译器而异。如果您想编写可移植代码,请使用int。如果你想创建一个小的结构,或者一个固定字节数的结构,或者一个位在固定位置的结构,不要使用位域。创建一个名为 flags 之类的 uint8_t 成员并定义宏以用作位掩码。

【讨论】:

  • 你的意思是unsigned intuint8_t 未签名,int 已签名,混合使用不好。
  • 我个人没有在代码中使用过位域,但如果是 1 位位域,符号是否重要?
  • @tomlogic 是的,签名很重要。 1 位有符号字段具有一个符号位和零值位。因此,在 MISRA C 和其他标准中明确禁止使用 1 位签名字段。
【解决方案3】:

正如其他人提到的可移植性问题等,如果您不知道可以通过警告编译指示禁用警告:
https://docs.microsoft.com/en-us/cpp/preprocessor/warning?view=vs-2019

#pragma warning(push)
#pragma warning(disable: 4214) // warning C4214: nonstandard extension used: bit field types other than int
typedef struct my{
    const char *name;
    uint8_t is_alpha : 1;   
    uint8_t is_hwaccel : 1; 
    uint8_t x_chroma_shift; 
    uint8_t y_chroma_shift; 
} mystr; 
#pragma warning(pop)

您还可以在项目属性中禁用特定警告,但它们是项目范围的。这样您就可以按数据类型控制它们。

然后,如果您不确定 100% MSVC 将为这些生成什么样的二进制代码,请在调试器中运行它并查看“反汇编视图”(在它被访问的位置中断),或者加载您的可执行文件(带有符号的 PDB 文件)在 IDA Pro、Ghidra 等反汇编程序中。

【讨论】:

    猜你喜欢
    • 2011-08-24
    • 2019-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    相关资源
    最近更新 更多