1. 程式人生 > >C/C++位域知識小結

C/C++位域知識小結

幾篇較全面的位域相關的文章:

本文主要對位域相關知識進行了一下梳理,參考如下:

C/C++中以一定區域內的位(bit)為單位來表示的資料成為位域,位域必須指明具體的數目。

位域的作用主要是節省記憶體資源,使資料結構更緊湊。

1. 一個位域必須儲存在同一個位元組中,不能跨兩個位元組,故位域的長度不能大於一個位元組的長度。

如一個位元組所剩空間不夠存放另一位域時,應從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:

複製程式碼
   struct BitField
   {
      unsigned int a:4;  //佔用4個二進位制位;
      unsigned int
:0; //空位域,自動置0; unsigned int b:4; //佔用4個二進位制位,從下一個儲存單元開始存放; unsigned int c:4; //佔用4個二進位制位; unsigned int d:5; //佔用5個二進位制位,剩餘的4個bit不夠儲存4個bit的資料,從下一個儲存單元開始存放; unsigned int :0; //空位域,自動置0; unsigned int e:4; //佔用4個二進位制位,從這個儲存單元開始存放; };
複製程式碼

2. 取地址操作符&不能應用在位域欄位上;

3. 位域欄位不能是類的靜態成員;

4. 位域欄位在記憶體中的位置是按照從低位向高位的順序放置的;

複製程式碼
struct BitField
  {
    unsigned char a:2;  //最低位;
    unsigned char b:3;
    unsigned char c:3;  //最高位;
  };
  union Union
  {
    struct BitField bf;
    unsigned int n;
  };
  union Union ubf;
  ubf.n = 0;    //初始化;
  ubf.bf.a = 0; //二進位制為: 000
  ubf.bf.b = 0; //二進位制為: 000
  ubf.bf.c = 1
; //二進位制為: 001 printf("ubf.bf.n = %u\n", ubf.n);
複製程式碼

位域中的位域欄位按照從低位向高位順序方式的順序來看,那麼,a、b、c這三個位域欄位在記憶體中的放置情況是:

最高位是c:001,中間位是b:000,最低位是a:000;所以,這個位域結構中的8二進位制內容就是: 00100000,總共8個位,其十進位制格式就是32;

實際上打印出來的ubf.n值就是32;

ubf.n = 100; //二進位制為: 01100100

printf("ubf.bf.a = %d, ubf.bf.b = %d, ubf.bf.c = %d\n", ubf.bf.a, ubf.bf.b, ubf.bf.c);

此時,對於位域ubf.bf來說,其位於欄位仍然按照從低位向高位順序方式的順序放置,則,最高位是c:011,中間位是b:001,最低位是a:00;

所以,ubf.bf.a = 0; ubf.bf.b = 1; ubf.bf.c = 3;

實際上打印出來的結果也的確如此;不夠儲存下一個位域的4位,故設為空位域,不使用,自動置0;e從第四個位元組處開始存放,佔用4位;

5. 位域的對齊

1. 如果相鄰位域欄位的型別相同,且其位寬之和小於型別的sizeof大小,則後面的欄位將緊鄰前一個欄位儲存,直到不能容納為止;

2. 如果相鄰位域欄位的型別相同,但其位寬之和大於型別的sizeof大小,則後面的欄位將從新的儲存單元開始,其偏移量為其型別大小的整數倍;

3.如果相鄰的兩個位域欄位的型別不同,則各個編譯器的具體實現有差異,VC6採取不壓縮方式,GCC和Dev-C++都採用壓縮方式;

4. 整個結構體的總大小為最寬基本型別成員大小的整數倍。

5. 如果位域欄位之間穿插著非位域欄位,則不進行壓縮;(不針對所有的編譯器)

複製程式碼
  struct BFA
  {
    unsigned char a:2;
    unsigned char b:3;
    unsigned char c:3;
  };
  struct BFB
  {
    unsigned char a:2;
    unsigned char b:3;
    unsigned char c:3;
    unsigned int  d:4;  //多出來這個位域欄位;
  };
複製程式碼

sizeof(BFA)=1, sizeof(BFB)=8;

這也說明了第三點中"相鄰兩個位於欄位型別不相同時,VC6採取不壓縮的方式"

6. 當要把某個成員說明成位域時,其型別只能是int,unsigned int與signed int三者之一(說明:int型別通常代表特定機器中整數的自然長度。short型別通常為16位,long型別通常為32位,int型別可以為16位或32位.各編譯器可以根據硬體特性自主選擇合適的型別長度.見The C Programming Language中文 P32)。

儘管使用位域可以節省記憶體空間,但卻增加了處理時間,在為當訪問各個位域成員時需要把位域從它所在的字中分解出來或反過來把一值壓縮存到位域所在的字位中.

複製程式碼
#include <iostream>
 #include <memory.h>
 using namespace std;
 struct A
 {
     int a:5;
     int b:3;
 };
 int main(void)
 {
     char str[100] = "0134324324afsadfsdlfjlsdjfl";
         struct A d;
     memcpy(&d, str, sizeof(A));
     cout << d.a << endl;
     cout << d.b << endl;
     return 0;
 }
複製程式碼

在32位x86機器上輸出:

高位 00110100 00110011   00110001    00110000 低位
       '4'       '3'       '1'          '0'  
其中d.a和d.b佔用d低位一個位元組(00110000),d.a : 10000, d.b : 001

解析:在預設情況下,為了方便對結構體內元素的訪問和管理,當結構體內的元素長度都小於處理器的位數的時候,便以結構體裡面最長的元素為對其單位,即結構體的長度一定是最長的資料元素的整數倍;如果有結構體記憶體長度大於處理器位數的元素,那麼就以處理器的位數為對齊單元。由於是32位處理器,而且結構體中a和b元素型別均為int(也是4個位元組),所以結構體的A佔用記憶體為4個位元組。

上例程式中定義了位域結構A,兩個個位域為a(佔用5位),b(佔用3位),所以a和b總共佔用了結構A一個位元組(低位的一個位元組)。

當程式執行到14行時,d記憶體分配情況:

 高位 00110100 00110011   00110001    00110000 低位
       '4'       '3'       '1'          '0'  
 其中d.a和d.b佔用d低位一個位元組(00110000),d.a : 10000, d.b : 001

 d.a記憶體中二進位制表示為10000,由於d.a為有符號的整型變數,輸出時要對符號位進行擴充套件,所以結果為-16(二進位制為11111111111111111111111111110000)

 d.b記憶體中二進位制表示為001,由於d.b為有符號的整型變數,輸出時要對符號位進行擴充套件,所以結果為1(二進位制為00000000000000000000000000000001)

複製程式碼
#include "stdio.h"

void main(int argn ,char *argv)
{
    struct     test {
        unsigned a:10;
        unsigned b:10;
        unsigned c:6;
        unsigned :2;//this two bytes can't use
        unsigned d:4;
        }data,*pData;
    data.a=0x177;
    data.b=0x111;
    data.c=0x7;
    data.d=0x8;
    
    pData=&data;
    printf("data.a=%x data.b= %x data.c=%x data.d=%xn",pData->a,pData->b,pData->c,pData->d);//位域可以使用指標

    printf("sizeof(data)=%dn",sizeof(data));   //4 bytes ,最常用的情況

    struct testLen{
    char a:5;
    char b:5;
    char c:5;
    char d:5;
    char e:5;
    }len;
    
    printf("sizeof(len)=%dn",sizeof(len));     //5bytes 規則2

    struct testLen1{
        char a:5;
        char b:2;
        char d:3;
        char c:2;
        char e:7;
        }len1;
    printf("sizeof(len1) =%dn",sizeof(len1));    //3bytes 規則1

    struct testLen2{
        char a:2;
        char :3;
        char b:7;
        long d:20; //4bytes
        char e:4;
        }len2;
    printf("sizeof(len2)=%dn",sizeof(len2));  //12 規則3,4,5,總長為4的整數倍,2+3 佔1byte,b佔1bye 由於與long對其,2+3+7 佔4位元組,後面 d 與 e進行了優化 佔一個4位元組


    struct testLen3{
        char a:2;
        char :3;
        char b:7;
        long d:30;
        char e:4;
        }len3;
    printf("sizeof(len3)=%dn",sizeof(len3));//12 規則3,4,5,總長為4的整數倍,2+3 佔1byte,b佔1bye 由於與long對其,2+3+7 佔4位元組,後面 d佔一個4位元組,為了保證與long對其e獨佔一個4位元組
}
複製程式碼

另:C++標準庫提供了一個bitset 類模板,它可以輔助操縱位的集合。在可能的情況下應儘可能使用它來取代位域。

相關推薦

C/C++知識小結

幾篇較全面的位域相關的文章: 本文主要對位域相關知識進行了一下梳理,參考如下: C/C++中以一定區域內的位(bit)為單位來表示的資料成為位域,位域必須指明具體的數目。 位域的作用主要是節省記憶體資源,使資料結構更緊湊。 1. 一個位域必須儲存在同一個位元組中,不能跨兩個位元組,故位域的長

C語言的一些知識

結果 完整 signed 編譯 har 占用 之間 相對 方式 有些信息在存儲時,並不需要占用一個完整的字節, 而只需占幾個或一個二進制位。例如在存放一個開關量時,只有0和1 兩種狀態,用一位二進位即可。為了節省存儲空間,並使處理簡便,C語言又提供了一種數據結構,稱為“位域

C語言

有些資訊在儲存時,並不需要佔用一個完整的位元組, 而只需佔幾個或一個二進位制位。例如在存放一個開關量時,只有0和1 兩種狀態,用一位二進位即可。為了節省儲存空間,並使處理簡便,C語言又提供了一種資料結構,稱為“位域”或“位段”。所謂“位域”是把一個位元組中的二進位劃分為幾

C語言操作

 傳統的位域,可以方便的實現位操作,但是需要對結構體整體讀出時比較麻煩。如果有些場合需要對位進行操作,又有把結構體整體讀出需求時,往往讓人不知所措,這事可以用聯合體+結構體(位域)的方法實現。 位域的概念:     有些資訊在儲存時,並不需要佔用一個完整的位元組, 而只

20150127 【 ARM 】 C語言+聯合體

結構體位域struct Fpga{unsigned int a:1;unsigned int b:1;unsigned int c:1;}; 聯合體:多個成員共用一塊儲存空間(佔最大資料型別空間)同一時刻只能用一個成員union FPH{unsigned int p;unsigned char ch;};un

C語言

有些資訊在儲存時,並不需要佔用一個完整的位元組, 而只需佔幾個或一個二進位制位。例如在存放一個開關量時,只有0和1 兩種狀態, 用一位二進位即可。為了節省儲存空間,並使處理簡便,C語言又提供了一種資料結構,稱為“位域”或“位段”。所謂“位域”是把一個位元組中的二進位劃分為幾個不同的區域, 並說明每個區域的位

C語言的使用

C語言位域 VC2015 通過聯合體,可以管理一個字節的每一個位,這樣是為了結省內存,充分利用字節中的信息。union STATE { struct BITDATA { BOOL D0 : 1;//BOOL的取值範圍:0或-1 BOOL D1 : 1; BOOL D2 : 1

C語言結構體中冒號()用法

位域出現的原因是由於某些資訊的儲存表示只需要幾個bit位就可以表示而不需要一個完整的位元組,同時也是為了節省儲存空間和方便處理。   typedef struct  bit_struct {     int &n

C語言第9課——

有些資訊在儲存時,並不需要佔用一個完整的位元組,而只需佔幾個或一個二進位制位。 例如在存放一個開關量時,只有 0 和 1 兩種狀態,用 1 位二進位即可。 為了節省儲存空間,並使處理簡便,C 語言又提供了一種資料結構,稱為"位域"或"位段"。 所謂"位域"是把一個位元組中的二進位劃分

C語言_

“位域”是把一個位元組中的二進位劃分為幾個不同的區域,並說明每個區域的位數。 每個域有一個域名,允許在程式中按域名進行操作。這樣就可以把幾個不同的物件用一個字 節的二進位制位域來表示。    1.位域的定義和位域變數的說明      &nbs

C語言變數宣告加冒號的用法 稱為“”或“段“

 有些資訊在儲存時,並不需要佔用一個完整的位元組, 而只需佔幾個或一個二進位制位。例如在存放一個開關量時,只有0和1 兩種狀態, 用一位二進位即可。為了節省儲存空間,並使處理簡便,C語言又提供了一種資料結構,稱為“位域”或“位段”。所謂“位域”是把一個位元組中的二進位劃

C/C++ 位元組序/(Bit-fields)之我見

前言很早想說說這個問題了,經常也會有很多公司拿位域出來考人,呵呵要真的想弄清楚還要一點點的分析。這裡先看看網宿的一道筆試題目,這道題目我之前是複製網上的,結果不對,修改了一下,可以正確運行了,謝謝(imafish_i )提醒://假設硬體平臺是intel x86(little

C語言中利用共用體、結構體、實現操作

編寫過51(MCU)程式的同學都知道51架構的MCU支援位操作,這是一個很方便的特性,在讀取/修改暫存器某位的值時非常方便快捷。但其他架構的MCU大多都不支援該特性,即不支援位操作,所在在對暫存器中某一位進行操作的時候都是and/or兩個操作共同使用,在編寫程式時非常麻煩。

C語言中的結構體

例如:struct test {        int a:1;        int b:1;};       不是給a賦初值,在記憶體中儲存資料的最小單位一般是位元組,但有時儲存一個數據不必用一個位元組。這是一種位域的結構體,這個結構體中a佔用的是一個位元組中的1位,b也

C語言面試題——及大小端模式的理解

這裡涉及大小端的問題,我記為 “小高高,小弟弟(低低)”,就是: “小端模式,是指資料的高位儲存在記憶體的高地址中,資料的低位儲存在記憶體的低地址中” 這是記小端模式的,有點黃,不過好記!那麼大端模式就和這個相反嘍!!~~ 接下來就看一道面試題: #include<

C語言中bit field

在C語言中bit feild 位域. A bit field declaration is a struct or union member declaration。 an integer constant expression with a value greater

C語言移位知識小結

       關於C語言移位功能的知識小結如下:               1,進行2的n次方計算,使用移位效率會提升很多;               2,移位有時候會導致資料丟失,但有時候這正是我們要的功能;               3,右移位操作是不可移植的;

由一道題引出的C++問題

題目如下(來源於牛客網): struct s { int x: 3; int y: 4; int z: 5; double a; } 求sizeof(s).(答案為16位元組) 題目理解 首先說明題目中定義x,y,z

C詳解(轉貼)

二、位域的使用位域的使用和結構成員的使用相同,其一般形式為: 位域變數名·位域名 位域允許用各種格式輸出。main(){ struct bs { unsigned a:1; unsigned b:3; unsigned c:4; } bit,*pbit; bit.a=1; bit.b=7; bit.c=15;

的定義和使用 C Bit Fields

位域的定義和使用    有些資訊在儲存時,並不需要佔用一個完整的位元組, 而只需佔幾個或一個二進位制位。例如在存放一個開關量時,只有0和1 兩種狀態, 用一位二進位即可。為了節省儲存空間,並使處理簡便,C語言又提供了一種資料結構,稱為“位域”或“位段”。所謂“位域”是把一個位元組中的二進位劃分為幾個不同的區域