C語言【進位制、原反二補數、資料型別】

2023-11-16 12:00:26

C語言【進位制、原反二補數、資料型別】

1、二進位制、八進位制、十進位制、十六進位制在C語言中的使用(賦值及輸出)?

/**
	二進位制 
	賦值時以 0b 或 0B 開頭;
	輸出時沒有所屬預留位置, 十六進位制整數輸出也比較直觀
*/
int num_bin = 0b110;
printf("%d\n", num_bin);	// 以十進位制整數形式輸出
//其他進位制輸出形式略,總之就是沒有二進位制形式的輸出
/**
	八進位制
	賦值時以0(零)開頭;
	預留位置:%o (小寫字母o , 八進位制整數) 
*/
int num_oct = 0123;
printf("%o\n", num_oct);	// 以八進位制整數形式輸出
/**
	十進位制
	賦值時正常表示
	預留位置:%d 表示輸出形式為十進位制整數
*/
int num_deci = 123456;
printf("%d\n", num_deci);
/**
	十六進位制
	以0x或0X開頭
	預留位置: %x     輸出十六進位制整數(A-F輸出為小寫)
		   %X     輸出十六進位制整數(A-F輸出為大寫)
	       %#x    輸出0x樣式十六進位制整數
		   %#X    輸出0X樣式十六進位制整數
*/
int num_hex = 0xff;
printf("%x\n", num_hex);
printf("%#x\n", num_hex);
printf("%#X\n", num_hex);

拓展問題:有沒有浮點型別二/八/十六進位制的數的展示 ?輸出呢?

似乎有,似乎用處不大。來一段:

float hex_float = 0x1P3; 
printf("hex_float = %f\n", hex_float);  // 輸出為 hex_float = 8.000000

在這裡,0x1P3是一種用科學計數法表示十六進位制浮點數的方式。在這個例子中,1P3表示1乘以2的3次方,也就是8。

2、進位制轉換略。 遺留問題: 浮點數的進位制轉換?

3、機器數指一個數在計算機中儲存的二進位制原樣;真值指按規則編碼後表示的值,比如1001這個二進位制數,如果把最高位的1表示為符號位,則其真值為-1。

4、原反二補數是什麼及各自的轉換。

  • 原碼:最高位表示符號位(0正、1負)的機器數。

  • 反碼:正數反碼即原碼;負數反碼符號位不變,其他位取反。

    反碼存在的意義就是為了求二補數。

  • 二補數:正數的二補數即原碼;負數的二補數即反碼+1。

    二補數存在的意義就是為使計算機運算更方便,因為計算機沒有設計減法器,聽說減法器不如用二補數更簡潔和高效。

    ​ 二補數的設計原理是:讓負數原碼的絕對值和負數的二補數相加為全零(最高位溢位),這個補全後的數即為該儲存大小能表示的個數,2位元組的話這個數即為65536,這樣的話有效位數就全為0了。

    ​ 比如:2+(-2)=0。 -2的二補數離有效位全0少2;+2離有效位全0多了2,對於有效位全0來說剛好互補。

    ​ 這樣設計的好處為:作減法運算時,可視為正數和負數相加。

    ​ 運算時,符號位也參與運算。

    ​ 負數二補數轉原碼時,也可以直接取反後+1得到。

    /**
    	下面的程式碼中
    		short 佔兩個位元組,能表示65536個數,最高位溢位,有效位全0
    		-2的在記憶體中以二補數形式儲存,表示為十進位制即為65534,要用%u輸出
    		也可以想-2離有效位全0即65536少2,即65534
    */
    unsigned short num_byte2 = -2;
    printf("%hu\n", num_byte2);	// 輸出為 65534  hu表示無符號短整型
    
    short num_byte2_1 = -2;
    printf("%hu\n", num_byte2_1);	// 輸出為 65534  
    

    問題:參考上面的程式碼,下面的程式碼為什麼會這樣子輸出?

    unsigned short num_byte2 = -2;	// 這一步將num_byte2轉換為65534
    printf("%u\n", num_byte2);		// 輸出為 65534
    
    short num_byte2_1 = -2;			// 在這一步num_byte2_1還是-2
    printf("%u\n", num_byte2_1);	// 輸出為 4294967294  轉換為無符號時short佔不下了,按四個位元組來,就變成了 4294967296-2, 即 4294967294
    

5、基本資料型別

  • 整型


    • 短整型 short ---------- 2Byte


      有符號短整型 signed short / short 預留位置為: %hi 表示範圍:-32768到32767 字面量無尾綴

      無符號短整型 unsigned short 預留位置為: %hu 表示範圍:0到65535 字面量無尾綴表示


    • 整型 int ---------- 16位元機 2Byte; 32位元機 4Byte


      有符號整型 signed int / int 預留位置: %d 表示範圍: 根據位數決定

      ​ 一般拼寫上一個沒超過int範圍的數預設字面量的型別為int,除非在字面量後面加尾綴。

      無符號整型 unsigned int 預留位置 %u 表示範圍: 根據位數決定 字面量尾綴為u或U


    • 長整型 long ----------- 32位元機 4Byte; 64位元機 8Byte 問題: 我64位元機咋還是4Byte?  windows的問題。Linux就是8個。不同系統使用的資料模型不同,導致long表示的範圍不能確定無二。


      有符號長整型 signed long / long 預留位置:%ld 表示範圍:不做掌握 字面量尾綴 l或L

      無符號長整型 unsigned long 預留位置: %lu 表示範圍:不做掌握 字面量尾綴lu或ul


    • 長長整型 long long ------------ 8Byte


      有符號長長整型 signed long long / long long 預留位置: %lld 表示範圍:很大很大 字面量尾綴ll或LL

      無符號長長整型 long long 預留位置: %llu (l和u位置不可互換) 表示範圍:很大很大 字面量尾綴llu或LLU


    注意
    任何系統的pointer(指標型別)位數和系統一致,比如64位元即8Byte;       
    char、int、long long不隨系統改變; 
    儘量不使用long;
    想確保int為4Byte可以使用stdint.h庫裡的 int32_t 型別

  • 浮點型 浮點型沒有無符號表示。浮點數的底層是三段儲存的,符號位、指數部分、有效部分,具體轉計算機組成原理檢視。


    • 單精度浮點型 float --------- 4Byte


      表示範圍:1.2E-38 到 3.4E+38 有效小數位 6-9

      字面量尾綴fF,給不加小數點的字面常數尾綴f或F會報錯

      預留位置:對於printf(...)來說,單精度和雙精度都是 %f C99打修補程式後都可以為%lf

      對於scanf(...)來說,單精度只能為 %f


    • 雙精度浮點型 double --------- 8Byte


      表示範圍 2.3E-308 到 1.7E+308 有效小數位數 15-18

      加了小數點的字面量預設為double,無需尾綴

      預留位置:對於printf(...)來說,單精度和雙精度都是 %f C99打修補程式後都可以為%lf

      對於scanf(...)來說,雙精度只能為 %lf


    • 長雙精度浮點型 long double ------------ 32位元機 10Byte; 64位元機16Byte


      表示範圍 很大很大 有效小數位數18位元以上

      字面量尾綴lL,給不加小數點的字面常數尾綴f或F會表示為long

      預留位置:%Lf


    • 浮點數列印時預設保留六位小數,可自行調整。如下:

      double num_doub = 123456789.23956;
      // 注意: 這個保留的兩位是四捨五入而不是擷取 (我用的gcc,別的編譯器沒試過)
      printf("%20.2lf\n", num_doub);		// 總共輸出二十個字元,不夠前面補空格。小數點後保留兩位,如果整數位大於二十,則仍然完整輸出整數位,小數位保留兩位(注意.2後面是字母l,不是數位1)
      
      // %e 預留位置可以輸出浮點數的科學計數法表示形式(適用float和double) 長雙用%Le(L大寫)
      double num_double2 = 123.4;
      printf("%e\n", num_double2);
      

  • 字元型 char ------- 1Byte

    預留位置: %c

    不能存中文字元,想存中文字元用指標或陣列。

    本質就是一個整數。不同裝置把char預設為有符號/無符號的型別。一般是有符號,即 -128 到 127

  • 布林型 _Bool C89標準沒有布林型別。C99提供了_Bool型別,底層依然是整型。

6、資料型別轉換

  • 隱式轉換(自動型別轉換)

    short(2)/ char(1) ----> int(2/4) -----> unsigned int (2/4) --------> long(4/8) ------> unsigned long(4/8) ----> long long(8) ------> float(4) ------> double(8) ------> long double(10/32)

​ 浮點轉整型有可能出現溢位(如果整數很大)或者 精度缺失

  • 顯示轉換(強制型別轉換,略) 整數小轉大具體細節按二補數計算。涉及浮點數的小轉大不會。

    float num_f = 12.3f;
    double num_dou = (double) num_f;
    printf("%lf\n", num_dou);		// 輸出 12.300000
    

7、sizeof(...)的使用,格式預留位置,返回的型別等。

sizeof(型別/變數名/字面量/表示式)

如果不是檢視 型別或表示式 的大小,可以使用 sizeof 變數名/字面量

預留位置為 %zu 或 %d

返回型別為size_t,根據系統決定實際型別。

返回型別的位元組個數,如果檢視某個字面量的位元組佔用個數,查的是它預設的使用型別位元組數。

8、補充

1. 跳脫字元

\b 退格; \n 換行符; \r 回車符; \t 製表符; \加單雙引號或斜槓在特殊情況下跳脫為它們本身等

2. C語言中非0即為真,-1也是真。
3. <stdint.h> 和 <stdbool.h> 提供的型別,略。
#include<stdio.h>
#include<stdint.h>
// 精確寬度整數型別
// 64位元,很多計算機底層為long long  , %d 輸出會數值錯亂
int64_t e1 = 4500000000;