C語言進制轉換和位運算

進制基本概念

  • 什么是進制?

    • 進制是一種計數的方式,數值的表示形式
  • 常見的進制

    • 十進制、二進制、八進制、十六進制
  • 進制書寫的格式和規律

    • 十進制 0、1、2、3、4、5、6、7、8、9 逢十進一
    • 二進制 0、1 逢二進一
      • 書寫形式:需要以0b或者0B開頭,例如: 0b101
    • 八進制 0、1、2、3、4、5、6、7 逢八進一
      • 書寫形式:在前面加個0,例如: 061
    • 十六進制 0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F 逢十六進一
      • 書寫形式:在前面加個0x或者0X,例如: 0x45

進制轉換

  • 十進制轉成二進制

    • 除二反序取余法
    • 例如: 將十進制(97) 轉換為二進制數
  • 二進制轉成十進制

    • 權值法(依次從末尾開始乘以2的n次冪,在將值相加,n從0開始)
  • 十進制轉成八進制

    • 除八反序取余法
    • 例如: 將十進制(4567) 轉換為八進制數
  • 八進制轉成十進制

    • 權值法(依次從末尾開始乘以8的n次冪,在將值相加,n從0開始)
  • 十進制轉成十六進制

    • 除十六反序取余法
    • 例如: 將十進制(4567) 轉換為十六進制數
  • 八進制轉成十進制

    • 權值法(依次從末尾開始乘以16的n次冪,在將值相加,n從0開始)
  • 例如: 將十六進制(11d7) 轉換為十進制數

  • 快速轉換規律


  • 十進制的小數轉換成二進制,小數部分和2相乘,取整數,不足1取0,每次相乘都是小數部分,順序看取整后的數就是轉化后的結果

原碼反碼補碼

  • 計算機只能識別0和1, 所以計算機中存儲的數據都是以0和1的形式存儲的

  • 數據在計算機內部是以補碼的形式儲存的, 所有數據的運算都是以補碼進行的

  • 正數的原碼、反碼和補碼

    • 正數的原碼、反碼和補碼都是它的二進制(三碼合一)
  • 負數的原碼、反碼和補碼

    • 二進制的最高位我們稱之為符號位, 最高位是0代表是一個正數, 最高位是1代表是一個負數
    • 一個負數的原碼, 是將該負數的二進制最高位變為1
    • 一個負數的反碼, 是將該數的原碼除了符號位以外的其它位取反
    • 一個負數的補碼, 就是它的反碼 + 1
    • 例如: -12的原碼、反碼和補碼分別為
  0000 0000 0000 0000 0000 0000 0000 1100 // 12二進制
  1000 0000 0000 0000 0000 0000 0000 1100 // -12原碼
  1111 1111 1111 1111 1111 1111 1111 0011  // -12反碼
  1111 1111 1111 1111 1111 1111 1111 0100 // -12補碼
  • 負數的原碼、反碼和補碼逆向轉換
    • 反碼 = 補碼-1
    • 原碼= 反碼最高位不變, 其它位取反
  1111 1111 1111 1111 1111 1111 1111 0100 // -12補碼
  1111 1111 1111 1111 1111 1111 1111 0011  // -12反碼
  1000 0000 0000 0000 0000 0000 0000 1100 // -12原碼
  • 為什么要引入反碼和補碼
    • 就是計算機只能做加法運算, 不能做減法和乘除法, 所以的減法和乘除法內部都是用加法來實現的
    • 例如: 1 - 1, 內部其實就是 1 + (-1);
    • 例如: 3 * 3, 內部其實就是 3 + 3 + 3;
    • 例如: 9 / 3, 內部其實就是 9 + (-3) + (-3) + (-3);
  • 雖然反碼能夠滿足我們的需求, 但是對于0來說, 前面的負號沒有任何意義, 所以才引入了補碼
    • 由于int只能存儲4個字節, 也就是32位數據, 而計算的結果又33位, 所以最高位溢出了,符號位變成了0, 所以最終得到的結果是0
  // 1 - 1; 1 + (-1);
  0000 0000 0000 0000 0000 0000 0000 0001 // 1補碼
  1111 1111 1111 1111 1111 1111 1111 1111   // -1補碼
  ---------------------------------------
 10000 0000 0000 0000 0000 0000 0000 0000 // 計算結果補碼
  0000 0000 0000 0000 0000 0000 0000 0000 //  == 0

位運算符

  • 程序中的所有數據在計算機內存中都是以二進制的形式儲存的。
  • 位運算就是直接對整數在內存中的二進制位進行操作
  • C語言提供了6個位操作運算符, 這些運算符只能用于整型操作數


  • 按位與 &
    -規則: 一假則假


    • 總結:
      • 1.奇數與1&為1 ,偶數與1&為0 ;
      • 2.任一位與1&還是那一位
  • 按位或 |
    -規則: 一真則真


  • 按位取反 ~
    • 規則:真變假,假變真


  • 按位異或 ^
    • 相同為0,不同為1


    • 總結
      • 1.任何兩個相同的數異或之后都是0
      • 2.任何數與0異或之后還是那個數
      • 3.任何數與另外一盒數異或兩次還是原來的那個數
  • 按位左移 <<
    • 把整數a的各二進位全部左移n位,高位丟棄,低位補0
    • 由于左移是丟棄最高位,0補最低位,所以符號位也會被丟棄,左移出來的結果值可能會改變正負性
    • 規律: 左移n位其實就是乘以2的n次方


  • 按位右移 >>
    • 除符號位以外,整體右移,多出來的砍掉,缺少的用符號位補充
    • 規律: 右移n位其實就是除以2的n次方


內存分配

  • 1.定義變量的目的就是為了在內存中開辟一塊存儲空間
  • 2.定義變量時指定數據類型的目的就是為了告訴計算機需要開辟多大的存儲空間
    1. char在內存中占用一個字節, int在內存中占用4個字節, double在內存中占用8個字節
    • sizeof(char);sizeof(int);sizeof(double);

    • 1.計算機分配內存的規則: 從大到小的分配

    • 2.變量名稱對應的是變量占用內存最小的那個字節

    • 1.由于計算機只能識別0和1, 所以會把十進制的9先轉換為二進制的9

    • 左邊是二進制的高位 右邊是二進制的低位

    • 0000 0000 0000 0000 0000 0000 0000 1001

    • 2.給變量分配內存的時候是從內存地址比較大的開始分配

    • 所以計算機在存儲數據的時候, 也會從內存地址比較大的開始存儲

    • 會從轉換好的二進制高位開始依次存入分配好的內存中

 * &是專門用于取出變量地址   
    printf("&num1 = %p\n", &num1); // &num1 = 0060FEAC
    printf("&num2 = %p\n", &num2); // &num2 = 0060FEA8

char類型內存存儲細節

  • 1.由于計算機只能識別0和1, 所以不能直接將字符a存儲到內存中
    字符在計算機中存儲的其實是它對應的ASCII碼值

  • 2.C語言的規則: 不看怎么存只看怎么取

  • 注意點:

    • char類型占用1個字節, 所以只有8位可以存儲數據
    • ASCII碼表中字符對應的ASCII值是從0~127
    • 0111 1111 // 127
    • 0000 0001 // 1

    • 1000 0000
    • char類型的取值范圍 -2^7 ~ 2^7-1 / -128~127

    總結: 字符存儲的順序:
    1.根據字符在ASCII碼表中找到對應的十進制數
    2.將找到的十進制數轉換為二進制
    3.將轉換好的二進制存儲到內存中



// 要定定義一個函數實現用戶傳入小寫字母, 將其轉換為大寫字母
/*
*
* a --> 97
* A --> 65
*
* b --> 98
* B --> 66
*
* 通過觀察得出一個結論
* 無論是哪個字母的小寫和大寫之間的ASCII碼都相差 32
* 只要讓小寫字母的ASCII碼值減去32就是大寫字母的ASCII碼
*/
// char ch = 'a';
// char res = ch - 32;
// // 注意點: C語言不看怎么存, 就看怎么取
// printf("res = %c\n", res);//A

char res = upperCase('m');
printf("res = %c\n", res);
return 0;
}
// 該函數的功能是將小寫字母轉換為大寫字母
char upperCase(char ch){
// 1.安全校驗, 判斷用戶傳入的是否是一個字母
// 在企業開發中, 盡量不要寫數字
// 如果ASCII哪天變化了我們需要修改代碼
// if(ch < '97' || ch > '122'){
if(ch < 'a' || ch > 'z'){
printf("請傳入一個合法數據\n");
return ' ';
}
char res = ch - ('a' - 'A');
return res;

類型說明符

- 類型說明符
 - 類型說明符一般都是用于修飾int類型的
 1.說明長度的
  short
  long
  long long
  ------------------------------------
  char 1個字節  -2^7~2^7-1  -128~127
 short int 2個字節 -2^15~2^15-1
  int  4個字節  -2^31~2^31-1
 long long int 8個字節 -2^63~2^63-1
  • 由于說明長度的類型說明符一般都是用于說明int類型的, 所以在使用的時候可以省略int

// short --> %hi, long --> %li, long long --> %lli
short num1 = 123; // short == short int
printf("num1 = %hi\n", num1);
long num2 = 123; // long == long int
printf("num2 = %li\n", num2);
long long num3 = 123; // long long == long long int
printf("num3 = %lli\n", num3);

  • 2.說明符號位的
    • unsigned 無符號的:
    • 不把二進制的第一位當做符號位來使用, 所以只能存儲零和正數, 不能存儲負數
    • 注意點: 如果變量被unsigned修飾了, 那么取出的時候必須使用%u, %u就代表用無符號的方式取出
    • 應用場景: 存儲銀行存款, 學生的分數等不能出現負數的情況
    • signed 有符號的:
    • 默認int就是有符號的, 就可以保存負數,零,正數, 所以signed一般用不上
    • 0000 0000 0000 0000 0000 00000 0000 0000
    • 對于整數而言, 在內存中二進制的第一位就是符號位
    • 如果第一位是0, 代表當前的整數是一個正數
    • 如果第一位是1, 代表當前的整數是一個負數
    • 默認情況下所有的int類型都是有符號的, 也就是都會將第一位看做符號位, 也就是可以保存負數,零,正數
     unsigned int num2 = 6;
     unsigned int num3 = 0;
     printf("num1 = %u\n", num1);
     printf("num2 = %u\n", num2);
     printf("num3 = %u\n", num3); 
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容