c99 位域问题

http://www.cnblogs.com/my_life/articles/2293397.html


位域成员不能单独被取sizeof值(编译报错),我们这里要讨论的是含有位域的结构体的sizeof,只是考虑到其特殊性而将其专门列了出来。
C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作了扩展,允许其它类型类型的存在。使用位域的主要目的是压缩存储,其大致规则为:

1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。

 

和结构体一样,位结构体也是按照成员的最大长度字节来对齐分配空间的。


测试:
struct test
 {
  char a:1;
  char :2;
  long b:3;
  char c:2;
 };
 test t1;
 int len=sizeof(t1);   //len=12,前两个位域共用一个char空间,按第三个位域long扩展为4字节空间,最后一个位域占用一个char空间,按最长位域空间扩展为4字节。

 

struct test
{
char f1 : 3;
short f2 : 4;
char f3 : 5;
};
test t1;
int len=sizeof(t1); //len=6,第一位域占用一个char空间,按第二个位域short扩展为2字节空间,最后一个位域占用一个char空间,按最长位域空间扩展为2字节。

 

如果位域上的整形范围值是0,则下个位域从新的字节开始,前一字段后面空出的所有字节都不使用(即使是同类型的位域),如:

struct bs
{
    unsigned a:4;
    unsigned :0;      // 空域
    unsigned b:4;    // 从新字节开始存放
    unsigned c:4;
} ;

sizeof(unsigned) == 4

上面这个位域定义中,a占第一字节的4位,第一个字节的后4位以及后面的3个字节都填0表示不使用,b从新的字节开始,占用4位,c占用4位。上面位结构体大小为:8


struct test
 {
  char a:1;
  char :2;
  char b:3;
  long c:2;
 };
 test t1;
 int len=sizeof(t1);   //len=8

struct test
 {
  char a:1;
  char :2;
  char b:3;
  char c:2;
 };
 test t1;
 int len=sizeof(t1);   //len=1


<think>好的,我现在需要帮助用户解决关于“的类型无效”的问题。首先,我要回顾之前的对话历史。用户之前询问了“UINT24未定义标识符”,我详细解释了原因和解决方案,包括使用的方法。现在用户的新问题是关于的类型无效,这可能与之前的解决方案有关联,尤其是在C/C++中使用结构体时可能出现的错误。 首先,我需要明确用户的问题具体是什么情况下出现的。在C/C++中用于结构体或联合体中,允许将多个变量压缩到同一存储单元。当用户定义时,如果指定的类型不符合语言规范,就会出现“的类型无效”的错误。 接下来,我需要分析可能的原因。根据C/C++标准,的底层类型必须是整型,比如int、unsigned int、signed int或者_Bool(C99之后)。如果用户尝试使用其他类型,比如浮点数、指针、结构体或枚举,编译器就会报错。此外,编译器可能有特定的限制,比如是否支持非标准类型作为,或者是否有大小限制。 我需要考虑用户可能的代码示例。例如,用户可能定义了一个结构体,其中成员使用了无效的类型。例如: struct Example { float a : 4; // 错误:域类型不能是float }; 这种情况下,编译器会报错,因为float不是合法的域类型。 接下来,我应该列出常见的原因和对应的解决方案。首先,用户可能使用了非整型类型,解决方案是改用标准的整型类型,如unsigned int或uint8_t。其次,用户可能在使用自定义类型或typedef时没有注意到底层类型是否合法,需要检查typedef的定义。另外,某些编译器可能不支持某些扩展类型,比如GCC允许使用枚举或_Bool,但其他编译器可能不支持,导致错误。 还需要提到编译器相关的问题。不同的编译器可能有不同的限制,比如MSVC要求成员必须是int、unsigned int或signed int,而GCC支持更广泛的类型。用户需要注意编译器的文档。 此外,的大小超过基础类型的大小也是一个常见问题。例如,定义unsigned int a : 33;在32系统上会导致错误,因为unsigned int通常是32,无法容纳33。解决方案是使用更大的类型,如unsigned long long。 用户可能需要具体的代码示例来理解如何修正错误。例如,将错误的float类型改为unsigned int,或者调整大小以适应基础类型。 最后,总结问题,强调的使用限制和注意事项,帮助用户避免类似错误。同时,提醒用户查阅编译器文档,了解具体的支持情况。 在整理这些思路时,要确保语言口语化,避免使用专业术语过多,但又要准确。同时,结构清晰,分点列出原因和解决方案,便于用户理解和操作。需要检查是否有遗漏的情况,比如C++与C的差异,或者不同编译器的特殊支持,确保覆盖用户可能遇到的各种情况。</think>--- ### **的类型无效:问题解析与解决方案** 在 C/C++ 中,**(Bit Field)** 是一种通过结构体或联合体将多个变量压缩到同一存储单元的技术,常用于节省内存或硬件寄存器操作。但若域类型不符合规范,编译器会提示 **“的类型无效”**。以下是详细分析与解决方法: --- ### **1. 问题本质** 的底层类型必须满足以下条件: - **必须是整型**:如 `int`, `unsigned int`, `signed int`, `_Bool`(C99+)等。 - **不可为浮点型、指针、结构体等非整型类型**。 - **大小不能超过基础类型的数**(如 `unsigned int` 通常为 4 字节,即 32 )。 **示例错误代码**: ```c struct InvalidBitfield { float a : 4; // 错误:float 不是整型 char* b : 8; // 错误:指针不能作为域类型 }; ``` --- ### **2. 常见原因与解决方案** #### **(1) 使用了非整型类型** - **错误场景**: ```c struct Example { double value : 16; // 错误:double 是浮点型 }; ``` - **解决方案**: 改用标准整型(如 `unsigned int`, `uint32_t`): ```c struct Example { unsigned int value : 16; // 正确 }; ``` #### **(2) 使用了自定义类型或 typedef** - **错误场景**: ```c typedef enum { ON, OFF } State; struct Device { State status : 1; // 部分编译器报错(如 MSVC) }; ``` - **解决方案**: 检查 `typedef` 的底层类型是否为整型,或改用 `_Bool`/`int`: ```c struct Device { _Bool status : 1; // 正确(C99+) }; ``` #### **(3) 大小超过基础类型数** - **错误场景**: ```c struct Overflow { unsigned int a : 33; // 错误:32系统下 unsigned int 最大32 }; ``` - **解决方案**: 使用更大的基础类型(如 `unsigned long long`): ```c struct Overflow { unsigned long long a : 33; // 正确(需64支持) }; ``` #### **(4) 编译器兼容性问题** - **部分编译器限制**: - **MSVC**:仅支持 `int`, `unsigned int`, `signed int` 作为域类型。 - **GCC/Clang**:支持 `char`, `short`, `_Bool` 等扩展类型。 - **解决方案**: 统一使用 `unsigned int` 或 `int` 以提高兼容性。 --- ### **3. 正确用法示例** ```c // 示例1:标准定义 struct Register { unsigned int flag : 1; // 1标志 unsigned int value : 24; // 24数值 unsigned int : 7; // 7填充(无名) }; // 示例2:使用固定宽度类型(需包含 <stdint.h>) #include <stdint.h> struct SensorData { uint16_t id : 12; // 12ID uint16_t temp : 4; // 4温度值 }; ``` --- ### **4. 注意事项** 1. **内存对齐**:的总大小可能因编译器对齐规则而大于预期。 2. **可移植性**:的内存布局(顺序、字节序)依赖编译器和硬件,跨平台时需谨慎。 3. **性能影响**:频繁操作可能导致额外指令开销(如掩码、移操作)。 --- ### **总结** “的类型无效”通常由以下原因导致: - 类型不符合整型要求 - 大小超过基础类型数 - 编译器兼容性问题 **解决思路**: 1. 检查类型是否为标准整型(如 `unsigned int`)。 2. 确保大小不超过基础类型数。 3. 查阅编译器文档确认支持的类型范围。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值