C語言陷阱與技巧第13節,1位元組(Byte)一定等於8位(bit)嗎?C語言操作...

2020-11-25 IT劉小虎

C語言沒有類似於 Java 的「垃圾回收」等高級程式語言特性,也不像 python 那樣無需顯示聲明類型就能使用變量,因此在很多人看來,C語言有些「低級」。但是C語言的這些「低級」也是 C語言的優點——使用C語言開發程序,程式設計師能夠準確知道究竟使用了多少資源,以及哪些資源還在內存裡,哪些已經被釋放。換句話說,C語言程序具備資源的使用確定性

因此,C語言特別適合用於一些資源比較匱乏的項目開發中。在這些項目中,以嵌入式項目為代表,一般都需要嚴格控制內存的使用——使用 1 個字節(Byte)就能存放的值,絕對不定義 2 個字節寬度的變量。甚至,一些「摳門」的C語言程式設計師會將 1 個字節掰成若干個位(bit)使用。

所以,在C語言程序開發中,常常需要操作某個變量特定的位(bit),這對於C語言來說當然沒有任何難度,各種移位操作就能夠方便的解決該類需求,例如:

unsignedchar status;status |= 0x01 << 2;status &= ~0x01;上面第二行C語言代碼將 status 的第3個位(bit 2)設置為 1,第三行C語言代碼將 status 的第1個位(bit 0)設置為 0。可以看出,藉助於位運算,C語言可以比較簡單的操作 status 的指定位。不過,C語言這種操作位的方法有時候看起來不夠直觀——至少沒有直接賦值那麼直觀。

那C語言有沒有更加直觀的位操作方法呢?

上面的例子通過移位、以及或與非等操作實現對變量 status 的位操作,但是看起來卻不是那麼直觀,那麼C語言有沒有更加直觀的位操作方法呢?似乎可以藉助C語言的聯合體(union)和位域(bit field)語法,間接的實現位操作,請看下面的C語言代碼:

union convert{ unsignedchar status;struct __bits { unsignedchar bit0:1;unsignedchar bit1:1;unsignedchar bit2:1;unsignedchar bit3:1;unsignedchar bit4:1;unsignedchar bit5:1;unsignedchar bit6:1;unsignedchar bit7:1; }v; };

此例中 status 和 bits 結構體共享一個字節的內存空間,結構體 bits 利用C言中的位域語法將一個字節的內存空間拆分成 8 個位,這種情況下,要讀寫 status 的位就非常簡單了,請看下面的C語言示例代碼:

union convert cv;// 寫 status 的 bit 3cv.v.bit3 = 0;// 寫 status 的 bit 7cv.v.bit7 = 1;// 讀 status 的 bit 5r = cv.v.bit5;編寫 main() 函數,測試通過位域操作 status 的位,相關C語言代碼如下,請看:

int main() { union convert cv; cv.status = 0; cv.v.bit3 = 1; cv.v.bit1 = 1;printf("%d\n", cv.status);return0; }

main() 函數一開始將 status 置為 0,然後將它的 bit1 和 bit3 設置為 1,也就相當於將 status 設置為 0x0a,編譯並執行這段C語言代碼,得到如下輸出:

# gcc t.c# ./a.out 10一切與預期一致,這樣就實現了以「賦值」的形式,操作C語言中的位,而且看起來比「移位與或非操作」更加直觀,所以這樣的操作更好了?

事實上,有一些C語言程式設計師的確這麼用,至少我的一些同事喜歡這樣的位操作。

警惕「常識陷阱」

1 個字節(Byte)等於 8 個位(bit)似乎已經是程式設計師間的常識了,很少有人質疑這一點。但是作為C語言程式設計師,我們常常要在不同的硬體平臺上做底層開發,應該明白:1個字節等於8個位只是慣例而已,C標準並沒有定義這一點。有些編譯器並不遵守這個慣例,例如,在 Texas 的 C55x DSP 的平臺上,1 個字節等於 16 個位。在這個平臺上,各種數據類型佔用的位數有些奇怪:

以 long long 為例,在該平臺上 long long 之所以等於 40 bit,而不是我們常用的 64 bit,是因為它們的 ALU 是 40 bit 寬,因此編譯器規定 long long 為 40 bit 可以降低功耗和提升效率。

另外, 就算在 1 個字節等於 8 個位的硬體平臺上,單個字節的 8 個位是如何分布的也是沒有明確標準的。

相關焦點

  • C語言陷阱與技巧31節,都說void*指針是「萬能指針」,它萬能在哪
    例如 int 型指針告訴編譯器該地址處緊接著的 4 字節按照 int 型數據解釋,double 型指針高速編譯器接下來的 8 字節按照 double 型數據解釋。這裡假定int型變量佔用4位元組內存空間,double 型變量佔用 8 字節內存空間。
  • 深入理解C語言
    導讀:Dennis Ritchie過世了,他發明了C語言,一個影響深遠並徹底改變世界的計算機語言。一門經歷40多年的到今天還長盛不訓的語言,今天很多語言都受到C的影響,C++,Java,C#,Perl,PHP,Javascript等等。但是,你對C了解嗎?相信你看過本站的《C語言的謎題》還有《誰說C語言很簡單?》。
  • Go語言的學習筆記(第二章)
    ,1<<10表示將1的二進位表示向左移10位,也就是由1變成了10000000000,也就是十進位的1024。類型描述uint8無符號 8位整型 (0 到 255)uint16無符號 16位整型 (0 到 65535)uint32無符號 32位整型 (0 到 4294967295)uint64無符號 64位整型 (0 到 18446744073709551615)int8有符號 8位整型 (-128 到 127)int16有符號 16位整型 (-32768 到 32767)int32有符號 32位整型
  • C語言陷阱與技巧第8節,輸出適當的信息,有利於定位錯誤和異常代碼
    現在編譯這段C語言程序並執行,得到如下結果:# gcc t.c -g# ./a.out cond is true# ./a.out cond is false從輸出結果可以發現,C語言程序輸出了「cond is false」(模擬異常)。
  • C語言程序設計試題及答案
    A) &(*x)   B) x C) *x D) &*x13、設a,b,c都是int型變量,且a=3,b=4,c=5,則下面的表達式中,值為0的表達式是( )。
  • C語言基礎知識學習(一)
    c) 用戶標識符根據需要定義的標識符。一般用來給變量、函數、數組、文件等命名。用戶標誌符如果與C語言的關鍵字重名,系統報錯;若與標準庫函數重名,系統不報錯,但預定義標識符將會失去原意,代之以用戶新定義的含義。顯然如果後面用到這個函數將會報錯。
  • 51單片機基礎剖析(基於C語言)
    data:數據存儲區,只能用於聲明變量,不能用來聲明函數,該區域位於片內,採用8位地址線編碼,具有最快的存儲速度,但是數量被限制在128byte或更少。 使用方法:unsigned char data fast_variable=0; Idata:數據存儲區,只能用於聲明變量,不能用來聲明函數。
  • 從Go語言角度剖析關於計算機位的問題
    字節而一個字節,等於8位,1位元組=8位 。 一位,就是一個0或1,就是二進位,非0即1。一個字節,就是8個0或1,就像這樣,00000000,如果看到不足8個0或1,將前面都補成0,補夠8位。通常情況下,語言一般只操作到字節,很少操作到位。為什麼a是97雖然上述我們知道了,一個位表示的就是一個通電或者沒通電的電子元件。一個字節表示的是8個通電或者沒通電的電子元件的組合。但是這樣並沒有解決實際問題啊,我想存一個10,在加上一個20,進行加法計算,咋辦???
  • 自考「C語言程序設計」模擬試題十一
    一、單項選擇題(共30分,每題1分)  1.在PC機中,『\n』在內存佔用的字節數是(  )  A.1   B.2   C. 3   D.4  2.字符串「ABC」在內存佔用的字節數是(   )  A.3   B.  4
  • C語言相關文件的基本知識
    文件有不同的類型,在程序的設計中,主要有兩種文件; 1.程序文件;包括源程序文件(後綴為.c),目標文件(後綴為.obj),可執行文件(後綴為.exe)等,這類文件的內容是程序代碼。在輸入操作時,數據從文件流向計算機內存,在輸出操作時,數據從計算機流向文件(如印表機、磁碟文件)。文件是由作業系統進行統一管理的,無論是用Worcl打開或保存文件,還是工程序中的輸入輸出都是通過作業系統進行的。文件要有一個唯一的文件標識,以便用戶識別和引川。文件標識包括3部分(1)文件路徑(2)文件名主幹(3)文件後綴。
  • C語言陷阱與技巧第2節,使用inline函數可以提升程序效率,但是讓...
    不過,天下沒有免費的午餐,C語言程序要實現內聯函數的上述特性是要付出一定的代價的。普通函數只需要編譯出一份,就可以被所有其他函數調用,而內聯函數沒有嚴格意義上的「調用」,它只是將自身的代碼展開到被調用處的,這麼做無疑會使整個C語言代碼變長,也就意味著佔用更多的內存空間,以及更多的指令緩存。
  • 「C語言從入門到入土」必備C語言基礎筆記整理
    一、C語言1、什麼是C語言?C語言是人寫機器看的一種語言。C語言是高級語言中的低級語言。C語言貼近硬體。C語言的入門學習比較簡單。彙編語言——>B語言——>C語言2、C語言的特性首先C語言就是你的女朋友。無論你讓它幹什麼,它絕對不會自己找到方法。
  • C語言程序設計試題與答案B卷
    每小題1分,共20分)1、一個C語言程序是由( )。A)0 B)3    C)5    D)113、if語句的控制條件是( )。A)可構成多重循環結構 B)循環次數不可能為0C)循環次數可能為0 D)先執行後判斷17、設int x=1,a=9,b=6,c=7,d=8;則執行語句:if(a>b) if(c>d)x=2;else x=3; 後,x的值是( )。
  • 學校裡學不到的C語言教程之10:一定要會的移位和16進位轉換原理
    不過我們這次要說的移位操作比較簡單,也比較重要。這種算法在編碼/解碼過程中是經常會碰到的,那就是8位單字節數據的移位結果。它的實際用途可以用常見的字節內容顯示為16進位字符串的算法來做個示例。而 16 進位的轉換用移位操作可以有一個非常高效而巧妙的算法:一個字節是 8 位,能表示 256 個數據,轉換成16進位就要用兩個可見字符來表示,那麼實際上就是每個可見字符表示 256 個數據中的一半,也就是 8 位數據中的一半 -- 即 4 位數據。而4位二進位最多能表示 16 個數據(兩個16種可能性組合在一起就是 256 種,即 16x16=256)。
  • 自考「C語言程序設計」模擬試題十四
    _53      -ab      DO  WORD      IF       Case     int  2.在C語言中,非法的八進位是:(     )  A.018    B.016    C.017    D.0257  3.在TC中,基本int a[4]類型變量所佔的字節數是(     )  A.1    B.2
  • C語言陷阱與技巧第15節,為什麼每調用一次函數,就需要一次if判斷...
    file failed, %m\n");free(buf); }else{if(-1==read(fd, buf, sizeof(buf))){printf("read file failed, %m\n"); close(fd);free(buf); }else{printf("%s", buf);free(buf); close(
  • 定義只有一個數組成員的C語言結構體有什麼用?
    在C語言程序開發中,有經驗的程式設計師有時會定義只有一個數組成員的結構體,雖然語法簡單,但是卻常常讓初學者感到迷惑:這麼做有什麼好處嗎?struct ABC {unsigned long array[MAX];} abc;
  • C語言怎麼樣?今天聊聊C語言的發展史!
    這裡,我想說一句可能有點片面的話,就是:如今這世界上,凡是帶電的地方,可能都會有她(C語言)或者她的子孫的影子。 一、C語言發展史 1.
  • 開課吧:C語言現在的就業形勢如何?前景怎麼樣?
    根據近幾年的程序語言排行榜來看,C語言的排名一直很靠前,這是為什麼呢?同時 C 語言也可以像彙編語言一樣對位、字節和地址進行操作, 而這三者是計算機最基本的工作單元。第二:C語言的出現本來就是為了代替彙編從事底層操作,而目前現在所出的很多語言大都不能進行底層操作,這樣就使得C語言的地位不可動搖。
  • 詳解C語言數據類型:float與double
    因此,我查看了第一個XMM寄存器xmm0,然後:xmm0中的值之一,當解釋為雙精度值時,是1,恰好是我們傳遞給printf的值。同時,當將該寄存器中的值解釋為浮點數時,它們是這樣(巧合的是,我們得到1.875)。因此,轉換確實發生了。