C语言---自定义类型:结构体(4)

简介: C语言---自定义类型:结构体

C语言---自定义类型:结构体(3)https://developer.aliyun.com/article/1544453

位段的内存分配

那么位段时如何改变内存的分配的呢?

  1. 位段的成员可以是 int unsigned int signed int 或者是 char 等类型
  2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的⽅式来开辟的。
  3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使⽤位段。
//struct S
//{
//    char a : 3;
//    char b : 4;
//    char c : 5;
//    char d : 4;
//};
//int main()
//{
//    struct S s;
//
//    return 0;
//}
/*
因为这里的数据是char类型的,1个字节,8个比特位
那么我们先开辟8个比特位,我们先用,不够的话再开辟
 
1.给定了空间后,在空间内部是从左向右使用还是从右向左使用呢?这个是不确定的
c语言并没与规定这个方向
 
 
那么我们假设从右到左
 1  2  3  4  5  6  7  8---这里表示的是比特位的位置
    b  b  b  b  a  a  a
 
 
    放完a和b还只有一个比特位了,不够的话我们再开辟一个字节
 
 
    2.当剩下的空间不足以存放喜爱一个成员的时候,空间是浪费还是使用,这个是不确定的
    那么我们就假设:是浪费
    //那么1号位就浪费了
1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16
   b  b  b  b  a  a  a              c   c   c   c   c
 
 
   放完c之后,就放d,d要4个比特位,但是现在只剩下3个比特位了
   那我们就再次开辟一个字节
 
1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24 
   b  b  b  b  a  a  a              c   c   c   c   c              d   d    d   d   d
 
   此时s b c d都已经放好了,我们用了3个字节
   假如我们不浪费的话只要2个字节就够了
   那么我们来测试一下
*/
//struct S
//{
//    char a : 3;
//    char b : 4;
//    char c : 5;
//    char d : 4;
//};
//int main()
//{
//    struct S s;
//    printf("%zd\n", sizeof(struct S));//3
//    return 0;
//}
 
 
/*
这个结果和我们判断的是一样的,占了3个字节大小的空间
 
可事实真的是这样的么?
那么我们就再举个例子进行判断
*/
struct S
{
    char a : 3;
    char b : 4;
    char c : 5;
    char d : 4;
};
int main()
{
    struct S s = {0};//将每个比特位都设置为0
    s.a = 10;
    s.b = 12;
    s.c = 3;
    s.d = 4;
 
    printf("%zd\n", sizeof(struct S));
    return 0;
}
 
/*
//初始化的情况如下
1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24-----比特位
0  0  0  0  0  0  0  0  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
 
0  b  b  b  b  a  a  a  0   0   0   c   c   c   c   c   0   0   0   0   d   d   d   d
*/
/*
s.a = 10;
往a里面放10,,10的二进制序列就是1010,可是a只有3个比特位,这里的10是4个比特位,3个比特位放不下1010
那么我们只能从地位到高位进行存放,存的是010
 
s.b = 12;
往b里面放12,12的二进制位是1100,b是4个比特位,那么刚好放得下1100
 
s.c = 3;
往c里面放3,c占5个比特位,3的二进制是11,那么我们就将00011放进去
前三个比特位还是0
 
s.d = 4;
往d里面放4,4的二进制是100,d占4个比特位,那么我们就将0100放进去,第一个
 
1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24-----比特位
0  0  0  0  0  0  0  0  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
 
0  b  b  b  b  a  a  a  0   0   0   c   c   c   c   c   0   0   0   0   d   d   d   d
 
0  1  1  0  0  0  1  0  0   0   0   0   0   0   1   1   0   0   0   0   0   1   0   0
放置结果如上:
 
因为4个二进制位写一个16进制,那么我们将16进制表示出来
 
6     2     0     3       0       4
 
我们进行调试,和我们分析的是一模一样的
*/
/*总结:
在当前的vs环境下,开辟空间是从右向左使用,如果剩下的空间不够,那我们就浪费这些空间,再开辟一个字节
*/
 
 
 
 
/*
我们再将一开始的例子拿过来进行判断下
struct A
{
 int _a:2;
 int _b:5;
 int _c:10;
 int _d:30;
};
 
因为类型是int
那么我们开辟4个字节,23个比特位,但是a只要2个比特位,剩下30个比特位,
b用5个,还有25个比特位
c用10个,还有15个比特位
 
d说要用30个比特位,剩下的15个不够了
那么我们再开辟4个字节,就是32个比特位
那么我们给d用30个比特位,剩下2个
 
算下来我们总共开辟了8个字节,浪费了17个比特位
 
 
这就是我们之前为什么算出来是8个比特位了
 
 
*/

1.给定了空间后,在空间内部是从右向左使用

2.当剩下的空间不足以存放喜爱一个成员的时候,空间是浪费的

上面两种是不确定的,需要我们实时进行探究

位段的跨平台问题

  1. int 位段被当成有符号数还是⽆符号数是不确定的。
  2. 位段中最⼤位的数⽬不能确定。(16位机器最⼤16,32位机器最⼤32,写成27,在16位机器会

出问题。

  1. 位段中的成员在内存中从左向右分配,还是从右向左分配,标准尚未定义。
  2. 当⼀个结构包含两个位段,第⼆个位段成员⽐较⼤,⽆法容纳于第⼀个位段剩余的位时,是舍弃

剩余的位还是利⽤,这是不确定的。

总结:

跟结构相⽐,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。

位段的注意事项

位段的⼏个成员共有同⼀个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位

置处是没有地址的。内存中每个字节分配⼀个地址,⼀个字节内部的bit位是没有地址的。

所以不能对位段的成员使⽤&操作符,这样就不能使⽤scanf直接给位段的成员输⼊值,只能是先输⼊

放在⼀个变量中,然后赋值给位段的成员。

struct A
{
    int _a : 2;
    int _b : 5;
    int _c : 10;
    int _d : 30;
};
int main()
{
    struct A sa = { 0 };
    //scanf("%d", &sa._b);//这是错误的
 
    //正确的⽰范
    int b = 0;
    scanf("%d", &b);
    sa._b = b;//直接进行赋值
    return 0;
}
相关文章
|
23天前
|
存储 C语言
如何在 C 语言中实现结构体的深拷贝
在C语言中实现结构体的深拷贝,需要手动分配内存并逐个复制成员变量,确保新结构体与原结构体完全独立,避免浅拷贝导致的数据共享问题。具体方法包括使用 `malloc` 分配内存和 `memcpy` 或手动赋值。
30 10
|
22天前
|
安全 编译器 Linux
【c语言】轻松拿捏自定义类型
本文介绍了C语言中的三种自定义类型:结构体、联合体和枚举类型。结构体可以包含多个不同类型的成员,支持自引用和内存对齐。联合体的所有成员共享同一块内存,适用于判断机器的大小端。枚举类型用于列举固定值,增加代码的可读性和安全性。文中详细讲解了每种类型的声明、特点和使用方法,并提供了示例代码。
21 3
|
22天前
|
存储 大数据 编译器
C语言:结构体对齐规则
C语言中,结构体对齐规则是指编译器为了提高数据访问效率,会根据成员变量的类型对结构体中的成员进行内存对齐。通常遵循编译器默认的对齐方式或使用特定的对齐指令来优化结构体布局,以减少内存浪费并提升性能。
|
27天前
|
编译器 C语言
共用体和结构体在 C 语言中的优先级是怎样的
在C语言中,共用体(union)和结构体(struct)的优先级相同,它们都是用户自定义的数据类型,用于组合不同类型的数据。但是,共用体中的所有成员共享同一段内存,而结构体中的成员各自占用独立的内存空间。
|
27天前
|
存储 C语言
C语言:结构体与共用体的区别
C语言中,结构体(struct)和共用体(union)都用于组合不同类型的数据,但使用方式不同。结构体为每个成员分配独立的内存空间,而共用体的所有成员共享同一段内存,节省空间但需谨慎使用。
|
1月前
|
编译器 C语言 C++
C语言结构体
C语言结构体
25 5
|
1月前
|
编译器 Linux C语言
C语言 之 结构体超详细总结
C语言 之 结构体超详细总结
19 0
|
1月前
|
存储 编译器 Linux
深入C语言:探索结构体的奥秘
深入C语言:探索结构体的奥秘
|
1月前
|
存储 编译器 C语言
c语言回顾-结构体(2)(下)
c语言回顾-结构体(2)(下)
28 0
|
1月前
|
存储 编译器 程序员
c语言回顾-结构体(2)(上)
c语言回顾-结构体(2)(上)
28 0