1. 程式人生 > >詳細解釋2進位制,10進位制,16進位制,8進位制,36進位制

詳細解釋2進位制,10進位制,16進位制,8進位制,36進位制

本篇介紹C/C++語言中的進位制的概念,主要介紹2進位制、10進位制、16進位制,這三種是程式設計時必須掌握的也是最常用的。另外,介紹8進位制和36進位制,其中 36進位制在實際工程專案中會遇到。 (本文選自《C/C++學習指南》,邵發,附錄“2進位制,10進位制,16進位制”)

 權利宣告:作者擁有本書的全部權利。作者授權任何人都可以自由轉載本網站釋出的內容,但轉載時必須遵守以下限制: ①轉載時必須全文轉載,不得有任何修改,必須包含“權利宣告”和“官網地址” ② 僅限於網路轉載,即最終結果公佈於網路上。凡是不遵守以上兩條的轉載行為視為侵權行為。除非本人允許,任何人不得將本網站內容內容用於任何的其他用途。 

官網地址:http://www.afanihao.cn/  留言請到http://www.afanihao.cn/kbase/

1.1         引例一

先給出一段程式碼,請讀者現在立即編譯執行一遍,觀察結果。

#include <stdio.h>
void main()
{
       int a = 'A';
       int b = 65;
       int c = 0x41;
       printf("%d, %d, %d \n", a, b, c);
}

如果你還沒有動手編譯,那麼請立即終止閱讀本書,因為本書不是為太懶的人準備的。所有程式碼和示例,請讀者務必自己手打一遍,不要拷貝。如果你是拷貝過去的,請立即燒掉本書,謝謝。

你會發現,輸出結果為:

是的,變數a,b,c的值完全相同。實際上,這三種初始化(賦值)方法是完全等價的,只是寫法不一樣而已。你用哪一種辦法都可以。

1.2         引例二

再給出另一段程式碼,請立即編譯和執行一下:

#include <stdio.h>
void main()
{
       char  a = 65;
       printf("%d,  %02X ,  %c \n",  a,  a,  a);
}

它的執行結果為:

是的,對於同一個整數a,當它作為十進位制顯示時,顯示為65;當作為十六進位制顯示為,顯示為41,當作為字元顯示時,顯示A。

1.3         引例三

如果上面的例子給你的印象還不夠深刻,再嘗試一個例子:

#include <stdio.h>
void main()
{
       // 以下變數a和b的值是相同的
       int a = 0x12345678;
       int b = 305419896;
       printf("%d, %d \n", a, b);
 
       // buf的內容為"ABC"
       char buf[4] = { 0x41, 66, 'C' , 0};
       printf("%s \n", buf);
}


結果為:

1.4         整型變數的2進製表示

本節內容對理解本章乃至全書都極為重要,如果你理解了,那麼所謂進位制問題對你就不再是個問題。

首先,在第三章中已經明確的強調,每個變數都是具有一個記憶體地址的。對於char型變數來說,在記憶體中佔了1個位元組。對於int型變數來說,在記憶體中佔了4個位元組。為了讓你更容易的理解,我們就先從char開始吧。

然後,我們看一下在計算機的記憶體裡,倒底是怎麼儲存的。我們從最最簡單的數開始。例如,定義一個變數 char  a = 13,此變數a佔了一個位元組的記憶體。在記憶體中,一個位元組有8個位(bit),每一個位可以是1或0。那麼a的表示為:

0

0

0

0

1

1

0

1

就是說,在實體記憶體中,它就是這麼儲存的。至於物理上如何表示1,如何表示0,讀者是不需要關心的。你可以簡單地認為一個位就對應一個“開關”,1表示開啟,0表示關閉。以後,我們就稱它的按位表示為 0000 1101 。

所以,char  a = 13 或者char  a = 0x0C ,這兩種寫法表示的意思是一樣的:分配一個變數,對應一個位元組,位元組的按位物理表示為 0000 1101。

明白了嗎?所謂10進位制還是16進位制是對人類而言的,不是同的說法。但是對於計算機而言,要儲存這個數值,就是要用8個位(對應8個物理開關)。這是哲學上的“形式和內容”的關係。

反過來,已經知道一個變數a的記憶體表示為 0000 1101,我們想在控制檯上把它的值顯示出來。那麼可以按10進位制顯示,也可以按16進位制顯示。

對你是小學生水平,那好吧,作為程式設計師我只好給按10進位制顯示給你了。

printf (" %d  ",  a);

如果你有碰巧看過本書,那好吧,我給按16進位制顯示:

printf(" %02X ", a);

1.5         進位制換算

這一節介紹的是數學裡的內容。作者的數學水平不高,在這裡只能讓你大概地理解一下。實際上,正如作者一再強調的,程式設計不需要太高的數學水平,幾乎對數學是沒有要求的。

首先,說說從16進位制到10進位制的換算。我們知道,0x41(十六進位制) 和65(十進位制)是等價的。那麼怎麼手工計算呢?下面給出示例:(以下不是程式碼,是在草稿紙的手算方法

0x41  =  4 * 16  + 1  = 65

0x12345678 = 1 * 167 + 2 * 166  + 3*165 + 4 * 164 + 5 * 16+ 6 * 162 + 7 *161 + 8 = 305419896

可以看出,對於16進位制,每一個數字上的權重就是 16n-1  (即16的n-1次方)

然後,說說從2進位制到10進位制的換算。

0000 1101 =   0 + 0 + 0 + 0 + 8 + 4 + 0 + 1 = 13

或者嚴格一點:

0000 1101 =   0 + 0 + 0 + 0 + 23 + 22+ 0 + 1 = 13

可以看出,對於2進位制,每一個數字上的權重就是2n-1(即2的n-1次方)

1.6         如何列印2進位制

在printf引數中,使用控制符%d可以按10進位制列印,使用%X可以按16進位制列印,那麼,有沒有按2進位制列印呢?

很遺憾,printf不能直接列印二進位制。為了彌補這個遺憾,作者貢獻一個按2進位制列印的函式。

#include <stdio.h>
 
// 把一個整數轉成二進位制字串
// value: 輸入整數
// buf: 輸出字串
// num_of_bits: 指定要列印的位數
void to_binary(unsigned int value, char buf[], int num_of_bits)
{
       for(int i=0; i<num_of_bits; i++)
       {
              unsigned int mask = 1 << (num_of_bits -1 - i);
              if ( value & mask)
                    buf[i] = '1';
              else
                    buf[i] = '0';
       }
       buf[num_of_bits] = 0;
}
 
void main()
{
       char buf[33];
       to_binary(135, buf, 8);
       printf("%s \n", buf);
}


1.7         8進位制

8進位制在工程實際中一般不會用到,這個用法沒有價值。和前面的類似,8進製表示每個數字的權重是8n-1(即8的n-1次方)。例如,15(八進位制)等於13(十進位制)。

在C/C++語言中,八進位制的字面常量以0開頭。例如下面的程式碼,

#include <stdio.h>
void main()
{
       int a = 015; // 以0開頭表示八進位制
       int b = 0x0D; // 以0x開頭表示十六進位制
       int c = 13;  // 十進位制
 
       printf("%d, %d, %d \n", a, b, c);
}


1.8         36進位制

正如序列 0, 1, 2, ..., 9, A, ..., F來表示16進位制一樣,用序列0, 1, 2, ...,9, A, B, ..., Y, Z來表示36進位制。其運算方法也完全是一樣的,每一個數字的權重是36n-1(36的n-1次方)。

例如,(以下不是程式碼,是草稿紙上的手算方法)

2Z = 36 * 2  + 35 = 107

事實上,36進位制在工程實踐中是一個很有用的知識。比如,同樣用4個字元來表示數字,使用10進位制可以表示0000~9999,使用16進位制可以表示0000~FFFF,使用36進位制可以表示0000~ZZZZ。可以,使用36進位制的表示能力最強。