日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C语言 位域的使用

發布時間:2024/1/23 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言 位域的使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • 什么是位域
  • 位域的定義
  • 位域的使用
  • 使用位域的注意點(重要)
  • 實際應用

什么是位域

有些信息在存儲時,并不需要占用一個完整的字節,而只需占幾個或一個bit。例如在存放一個開關量時,只有 0 和 1 兩種狀態,用 1 bit即可。為了節省存儲空間,并使處理簡便,C 語言又提供了一種數據結構,稱為"位域"或"位段"。

所謂"位域"是把一個字節中的二進制位劃分為幾個不同的區域,并說明每個區域的位數。每個域有一個域名,允許在程序中按域名進行操作。這樣就可以把幾個不同的對象用一個字節的二進制位域來表示。

典型的應用場景:

  • 用 1 位二進位存放一個開關量時,只有 0 和 1 兩種狀態。
  • 讀取外部文件格式——可以讀取非標準的文件格式。例如:9 位的整數。
  • 結構體中部分成員可能的賦值較小只需要用到1位或幾位,可以把這類成員湊到一起減少整個結構體占用的空間。
  • 可巧妙用于位操作

位域的定義

位域定義與結構定義相仿,其形式為:

struct 位域結構名 {位域列表 };

其中位域列表的形式為:

type [member_name] : width ;

其中 type :類型說明符; member_name: 位域名; width :位域長度;

例如:

struct TESTA {char a:3;char b:5;char c:4;char d:4; };

char 類型變量大小為一個字節(八位), 取值范圍為(-128, 127)。在上述位域的定義中,
a 只取三位,取值范圍為(-4, 3)。如果 a 為無符號型( unsigned char), 則取值范圍為(0, 7)。

位域的使用

位域的使用和結構成員的使用相同,其一般形式為:
位域變量名.位域名

位域變量指針名->位域名
位域允許用各種格式輸出。

示例:

int main() {struct bs{unsigned a:1;unsigned b:3;unsigned c:4;} bit,*pbit;bit.a=1; /* 給位域賦值(應注意賦值不能超過該位域的允許范圍) */bit.b=7; /* 給位域賦值(應注意賦值不能超過該位域的允許范圍) */bit.c=15; /* 給位域賦值(應注意賦值不能超過該位域的允許范圍) */printf("%d,%d,%d\n",bit.a,bit.b,bit.c); /* 以整型量格式輸出三個域的內容 */pbit=&bit; /* 把位域變量 bit 的地址送給指針變量 pbit */pbit->a=0; /* 用指針方式給位域 a 重新賦值,賦為 0 */pbit->b&=3; /* 使用了復合的位運算符 "&=",相當于:pbit->b=pbit->b&3,位域 b 中原有值為 7,與 3 作按位與運算的結果為 3(111&011=011,十進制值為 3) */pbit->c|=1; /* 使用了復合位運算符"|=",相當于:pbit->c=pbit->c|1,其結果為 15 */printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c); /* 用指針方式輸出了這三個域的值 */ }

結果:

使用位域的注意點(重要)

1、位域成員必須聲明為整型int、unsigned int或signed int類型,或是char,unsigned char,但不能是浮點型包括float,double
在ANSI C 中,這幾種數據類型是signed int和unsigned int;到了C99、C11新增了_Bool 的位字段。支持char一般是由于編譯器擴充的。

2、位域的長度不能超過它所依附的數據類型的長度,成員變量都是有類型的,這個類型限制了成員變量的最大長度,: 后面的數字不能超過這個長度。
例如:

struct k{int a : 33; }

這里就會報錯。

3、位域可以是無名位域,這時它只用來作填充或調整位置。無名的位域是不能使用的(沒有名稱當然沒法訪問)。例如:

struct k{int a:1;int :2; /* 該 2 位不能使用 */int b:3;int c:2; };

4、當無名位域且長度度為0時,表示下一個變量從下一段地址開始存儲。(下一段地址的具體位置還得根據結構體的內存對齊原則)
示例:

#include <stdio.h>struct k {char a : 2;char : 0;char b : 2;char c : 2; }; struct k test; int main() {char* ptr = (char *)&test;test.a = 1;test.b = 1;test.c = 1;printf("siezof(test)=%d\n",sizeof(test));printf("*ptr=%x ptr=%p\n", *ptr,ptr);printf("*ptr=%x ptr=%p\n", *(ptr+1), ptr + 1); }

結果:

上述例程中,位域a獨占一個字節,b和c共占一個字節。
b直接從下一個字節地址開始存儲了。

5、不能使用位域的地址,如:

struct k {char a : 2;char : 0;char b : 2;char c : 2; }; struct k test; printf("&test.a=%p\n",&test.a);//報錯 不能使用位域的地址

6、當結構體位域成員超出了限定的位數,將發生上溢(溢出中的一種)。

#include <stdio.h>struct {unsigned int age : 3; } Age;int main() {unsigned int* ptr = &Age;Age.age = 4;printf("Sizeof( Age ) : %d\n", sizeof(Age));printf("Age.age : %d\n", Age.age);Age.age = 7;printf("Age.age : %d\n", Age.age);Age.age = 8; // 二進制表示為 1000 有四位,超出了定義的3位長度printf("Age.age : %d\n", Age.age);printf("*p=%x\n", *ptr);return 0; }

結果:

注意,從最后的*p=0可以看出,溢出沒有導致其他位發現改變,否則這里就會等于8了。

7、位域可以和正常的結構體成員寫到一起。如:

struct {unsigned int age1 : 3;unsigned int age2 : 3;unsigned int age3;unsigned int age4 : 3; } Age;

8、一個位域存儲在N個字節中,如一個字節所??臻g不夠存放另一位域時,則會從下一單元起存放該位域。即不能跨字節存儲位域。
舉例:

struct pack {unsigned int a:12; unsigned int b:24; unsigned int c:6; };

sizeof(struct pack) = 8

一個unsigned int是4字節,a占了12位,還剩20字節,b需要24位,已經不夠了,又不能跨字節,因此b只能存在下一個unsigned int。

程序驗證:

struct pack {unsigned int a : 12;unsigned int b : 24;unsigned int c : 6; }; struct pack test; int main() {unsigned int* ptr = (unsigned int *)&test;test.a = 0xFFF;test.b = 0xFFFFFF;test.c = 0x3F;printf("*ptr=%08X\n", *ptr);printf("*(ptr+1)=%08X\n", *(ptr+1)); }

結果:

由上面的測試可以驗證,a和b之間的確有空的區域,即結果中的00000部分;

9、整個結構體空間占用大小
含位域的結構體占用存儲大小規則大致如下:

  • 如果相鄰位域字段的類型相同,且其位寬之和小于類型的sizeof大小,則后面的字段將緊鄰前一個字段存儲,直到不能容納為止
  • 如果相鄰位域字段的類型相同,但其位寬之和大于類型的sizeof大小,則后面的字段將從新的存儲單元開始,其偏移量為其類型大小的整數倍;
  • 如果相鄰的位域字段的類型不同,則各編譯器的具體實現有差異,VC6采取不壓縮方式,Dev-C++,GCC采取壓縮方式;
  • 如果位域字段之間穿插著非位域字段,則不進行壓縮(非位域字段保持其類型的對應大小);
  • 整個結構體的總大小為最寬基本類型成員大小的整數倍。
  • 第1,2點規則實際就是上面第8點所說的注意項問題,參考上文的示例即可。
    第3點相鄰的位域字段的類型不同,則各編譯器的具體實現有差異舉例:

    #include <stdio.h>struct test {char a : 2;char b : 3;int c : 1; };int main(void) {printf("%d\n", sizeof(struct test));return 0; }

    在Visual Studio 2019上運行結果:

    在Linux上GCC編譯運行結果:
    4
    (gcc version:4.8.2)

    第四點如果位域字段之間穿插著非位域字段,則不進行壓縮,指的是非位域字段不壓縮

    #include <stdio.h>struct test {char a : 2;char b : 3;int d ;int c : 1; };int main(void) {printf("%d\n", sizeof(struct test));return 0; }

    如上述示例程序struct test的d就是插在位域中的非位域字段,它的類型是int,所以d占4個字節,a和b共占4個字節,c單獨占4個字節,因此sizeof(struct test) = 12

    對于有位域的結構體占用存儲大小的問題,做一個精簡的方法總結:
    帶有’位域’的結構體并不是按照每個域對齊的,而是將一些位域 成員’捆綁’在一起做對齊的。"捆綁"還需注意跨字節問題,不能跨字節存儲位域。位域捆綁后,按照普通結構體占用大小的規則計算即可。

    實際應用

    示例:

    #include <stdio.h>union STATE {struct BITDATA{int D0 : 1;int D1 : 1;int D2 : 1;int D3 : 1;int D4 : 1;int D5 : 1;int D6 : 1;int D7 : 1;}BIT;int value; };int main(void) {int a = 0xFF;union STATE* sta;sta = &a;printf("sta.value=%02X\n",sta->value);printf("sizeof=%d\n", sizeof(sta->value));sta->BIT.D0 = 0;//給第一個位賦值printf("sta.value=%X\n", sta->value);printf("a=%X\n", a);return 0; }

    上述例程,使用union和位域實現對變量的某一bit位進行操作;該方式可用于計算機操作底層硬件寄存器。
    結果:

    參考:
    https://blog.51cto.com/u_15244533/2845234
    https://blog.51cto.com/u_14207158/2352294
    https://blog.51cto.com/u_9233403/2121352
    https://www.runoob.com/cprogramming/c-bit-fields.html
    https://blog.csdn.net/sty124578/article/details/79456405

    總結

    以上是生活随笔為你收集整理的C语言 位域的使用的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。