?? 第10章 位(bit)和字節(byte).txt
字號:
C語言編程常見問題解答
發表日期:2003年10月13日 已經有1344位讀者讀過此文
第10章 位(bit)和字節(byte)
位指的是二進制系統中的一位,它是最小的信息單位。位的用處可以從兩方面去分析:第一,計算機對位的值可以有任意多種解釋,例如表示"yes’’或"no”,或者表示磁盤是否已插入驅動器,或者表示某個鼠標鍵是否被按下;第二,將若干位的值連接起來后,就可以表示更復雜的數據,而且每增加一位,可以表示的可能的值的數目就會增加一倍。
換句話說,一位可以表示兩種可能的值,即“O”和“1”;兩位可以表示2×2或4種可能的值,即“00”,“01”,“10”和“11”;類似地,三位可以表示2×2×2或8種可能的值……。對計算機來說,位的這種特性既是最有力的支持——因為很復雜的數據(例如本書內容)可以被分解為位的表示后存儲起來,又是最大的限制——因為在現實生活中許多事物的值是不精確的,這樣的值無法用數目有限的若干位來表示。
程序員始終必須清楚每一項數據需要用多少位來表示。因為位作為單位太小,所以為了方便起見,大多數計算機所處理的信息單位是被稱為字節的位塊。字節是大多數計算機中最小的可尋址的信息單位,這意味著計算機給每一個字節的信息都賦予一個地址,并且一次只能存取一個字節的信息。一個字節中的位的數目可以是任意的,并且在不同的計算機中可以不同。最常見的情況是每個字節中有8位,即可以存放256個不同的值。8位這樣的長度非常適合于存放表示ASCII(the American Standard Code for Information Interchange)字符的數據。
下述程序可以顯示空格符以后的ASCII字符和PC機的圖形字符集:
# include <stdio. h>
void main (void);
void main()
{
/" Display ASCII char set " /
unsigned char space = '' ; /* Start with SPACE
char = 8 bits only * /
int ctr = 0;
printf(" ASCII Characters\n" )?
printf (" = = = = = = = = = = = = = = = =\n" ) ;
for (ctr = O; ctr + space <256; ctr+ + )
printf("%c", ctr + space);
printf ("\n");
}
請注意,變量ctr必須是int類型,而不能是char類型,因為char類型只含8位,只能存放從0至255之間的值(signed char類型只能存放從-128至127之間的值)。如果ctr是char類型,它就永遠不會存放256或比256更大的值,程序也就永遠不會結束。此外,如果你在非PC機的計算機上運行上述程序,那么程序所打印的非ASCII字符可能會導致亂屏。
因為計算機是以字節塊的方式工作的,所以大多數程序也以這種方式工作,有時,考慮到要存放的數據項的數目,或者移動每一位的信息所需的時間,節省內存空間就顯得很有必要。
這時,我們通常會用少于一個字節的空間來存放那些只有少數可能值的數據,這也就是本章要討論的主要內容。
10.1 用什么方法存儲標志(flag)效率最高?
標志的作用是對程序執行過程中的兩種或更多種選擇作出決定。例如,在執行MS-DOS的dir命令時,可以用“/w”標志使該命令在屏幕上顯示若干列文件名而不是每行只顯示一個文件名。在3.5中你可以看到另外一個例子,該例通過一個標志從兩種可能類型中選擇一種在一個聯合中使用。因為一個標志一般只有少數幾個(通常是兩個)值,所以,為了節省內存空間,通常不會將一個標志存放在一個屬于它自己的int或char類型中。
存儲標志值的效率是存儲空間和存取速度之間的一種折衷。存儲空間利用效率最高的存儲方法是用數目足夠的位來存儲標志值的所有可能值,但大多數計算機不能直接尋址內存中單獨的一位,因此標志值要從存放它的字節中提取。存取速度最快的存儲方法是將每個標志值都存放到一個屬于它自己的整型變量中,但是,當一個標志只需要一位存儲空間而變量的長度為32位時,那么其余的31位就全部浪費掉了,因此這種方法的存儲空間利用效率非常低。
如果標志的數目不多,那么使用哪種存儲方法是沒有關系的。如果標志的數目很多,那么最好將它們壓縮存儲在一個字符數組或整型數組中。這時,需要通過一種被稱為位屏蔽(bit masking)的過程來提取這些標志值,即屏蔽掉不需要的位,只處理所需的位。
有時,為了節省存儲空間,可能會將一個標志和另外一個值存放在一起。例如,如果一個整型的值小于整型所能表示的最大值,那么就可用它的高階位來存放標志;如果某些數據總是2或4的倍數,那么就可用它的低階位來存放標志。在3.5的例子中,就使用了一個指針的低階位來存放一個標志,該標志的作用是從兩種可能的類型中選擇一種作為該指針所指向的對象類型。
請參見:
10.2什么是“位屏蔽(bit masking)”?
10.3位域(bit fields)是可移植的嗎?
10.4移位和乘以2這兩種方式中哪一種更好?
10.2 什么是“位屏蔽(bit masking)”?
位屏蔽的含義是從包含多個位集的一個或一組字節中選出指定的一(些)位。為了檢查一個字節中的某些位,可以讓這個字節和屏蔽字(bit mask)進行按位與操作(C的按位與運算符為&)——屏蔽字中與要檢查的位對應的位全部為1,而其余的位(被屏蔽的位)全部為0。例如,為了檢查變量flags的最低位,你可以讓flags和最低位的屏蔽字進行按位與操作:
flags&1;
為了置位所需的位,可以讓數據和屏蔽字進行按位或操作(C的按位或運算符為|)。例如,你可以這樣置位flags的最低位:
flags = flags | 1;
或者這樣:
flags |= 1;
為了清除所需的位,可以讓數據和對屏蔽字按位取反所得的值進行按位與操作。例如,你可以這樣清除flags的最低位:
flags = flags& ~1;
或者這樣:
flags&=~1 ;
有時,用宏來處理標志會更方便,例10.2中的程序就是通過一些宏簡化了位操作。
例10.2 能使標志處理更方便的宏
/* Bit Masking * /
/ * Bit masking can be used to switch a character
between lowercase and uppercase * /
#define BIT_POS(N) ( 1U ?(N) )
#define SET_FLAG(N,F) ( (N) | = (F) )
#define CLR_FLAG(N,F) ( (N) &= - (F) )
#define TST_FLAGCN,F) ( (N) & (F) )
#define BIT_RANGE(N,M) ( BIT_POS((M) + 1- (N))-1<<(N))
#define BIT_SHIFTL(B,N) ( (unsigned)(B)?(N) )
#define BIT_SHIFTR(B,N) ( (unsigned)(B)?(N) )
#define SET_MFLAG(N,F,V) ( CLR_FLAG(N,F), SET_FLAG(N,V) )
#define CLR_MFLAG(N,F) ( (N) &= ~(F) )
#define GET_MFLAG(N,F) ( (N) & (F) )
# include <stdio. h>
void main()
{
unsigned char ascii_char = 'A'; /* char = 8 bits only */
int test_nbr = 10;
printf("Starting character = %c\n" , ascii_char);
/" The 5th bit position determines if the character is
uppercase or lowercase.
5th bit = 0 - Uppercase
5th bit = 1- Lowercase * /
printf ("\nTurn 5th bit on = %c\n" , SET_FLAG(ascii_char, BIT_POS(5)));
printf ("Turn 5th bit off = %c\n\n",CLR_FLAG(ascii_char, BIT_POS(5)));
printf ("Look at shifting bits\n");
printf (" = = = = = = = = = = = = = = = =\n" );
printf ("Current value = %d\n" , test_nbr)i
printf ("Shifting one position left = %d\n" ,
test_nbr = BIT_SHIFTL(test_nbr, 1) );
printf ("Shifting two positions right = %d\n" ,
BIT_SHIFTR(test_nbr, 2) );
}
宏BIT_POS(N)能返回一個和N指定的位對應的屏蔽字(例如BIT_POS(O)和BIT_POS(1)分別返回最低位和倒數第二位的屏蔽字),因此你可以用
#define A_FLAG BIT_POS(12)
#define A_FLAG BIT_P0S(13)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -