一 clang 分四步編譯main.c
這里用的clang/clang++ 分四步編譯main.c/main.cpp文件
1.1 C++源文件
#include <iostream>
int main() {
std::cout << "Hello Biter !" << std::endl;
return 0;
}
1.2 預處理、編譯、匯編、鏈接
clang或者clang++方式
### 1.2.1 預處理 命令: > > clang++ -E main.cpp -o main.ii
clang++ -S main.ii -o main.s
clang++ -c main.s -o mian.o
./main
1.3.1 產生中間文件
clang++ -save-temps main.cpp -o main
1.3.2 不保存中間文件
clang++ main.cpp -o main
# 二 持有ndk的交叉編譯工具 編譯main.c
2.1 預處理
armv7a-linux-androideabi29-clang++ -E main.cpp -o main.ii
armv7a-linux-androideabi29-clang++ -c main.s -o mian.o
armv7a-linux-androideabi29-clang++ mian.o -o main
由於計算機中符號和數字一樣,都必須用二進制數串來表示,因此,正負號也必須用0、1來表示。通常我們用最高的有效位來 表示數的符號(當用8位來表示一個整數時,第8位即為最高有效位,當用16位來表示一個整數時,第16位即為最高有效位。)0表示正號、1表示負號。
這種正負號數字化(0表示正號、1表示負號)的機內表示形式就稱為機器碼或者機器數,而相應的機器外部用正負號表示的數稱為真值。將一個真值表示成二進制字串的機器數的過程就稱為編碼。
無符號數沒有原碼、反碼和補碼一說。只有帶符號數才存在不同的編碼方式。帶符號整數有原碼、反碼、補碼等幾種編碼方式。
原碼即直接將真值轉換為其相應的二進制形式,而反碼和補碼是對原碼進行某種轉換編碼方式。
正整數的原碼、反碼和補碼都一樣。
負數的反碼是對原碼的除符號位外的其他位進行取反后的結果(取反即如果該位為0則變為1,而該位為1則變為0的操作)。而補碼是先求原碼的反碼,然后在反碼的末尾位加1 后得到的結果,即補碼是反碼+1。
IBM-PC中帶符號整數都采用補碼形式表示。
注意,只是帶符號的整數采用補碼存儲表示的,浮點數另有其存儲方式。
- 正數的補碼是其本身
- 負數的反碼,符號位不變,其余的按位取反
- 負數的補碼,反碼加1
對於字長為8位有符號的int,因為最高為符號位,占1位,所以最小為(11111111)2 = (-127)10,最大為(01111111)2 = (127)10;即其原碼范圍為:-127~127
有符號的8位二進制的原值表達范圍為:-127至127,此時共255個數字;然而,8位二進制 的補碼排列共有$2^8$ = 256個,0000 0000 至1111 1111 。
| 機器碼組合 | 范圍 | 個數 |
|---|---|---|
| 0000 0000 - 0111 1111 | 0 ~+127 | 128 |
| 10000000 | 多余的一種組合待定 |
1 |
| 1000 0001 - 1111 1111 | -1~-127 | 127 |
**10000000 **看似要被浪費掉了啊!其實不然,( 100000000 ) 2 = ( 2^7 ) 10 = ( 128 ) 10,這個組合要利用起來,不能太偏離數值意義,表示128,顯得更直觀。
**從大到小,依次減1看一下規律:**| 十進制 (字長8bit) | 原碼 | 反碼 | 補碼 |
|---|---|---|---|
| 127 | 0111 1111 | 0111 1111 | 0111 1111 |
| 126 | 0111 1110 | 0111 1110 | 0111 1110 |
| …… | …… | …… | …… |
| 10 | 0000 1010 | 0000 1010 | 0000 1010 |
| …… | …… | …… | …… |
| 2 | 0000 0010 | 0000 0010 | 0000 0010 |
| 1 | 0000 0001 | 0000 0001 | 0000 0001 |
| +0 | 0000 0000 | 0000 0000 | 0000 0000 |
| -1 | 1000 0001 | 1111 1110 | 1111 1111 |
| -2 | 1000 0010 | 1111 1101 | 1111 1110 |
| …… | …… | …… | …… |
| -10 | 10001010 | 11110101 | 11110110 |
| …… | …… | …… | …… |
| -127 | 11111111 | 10000000 | 10000001 |
| 待定 | 10000000 |
從遞減規律中,發現,**10000000 **表示-128更合適。
即規定:-128的補碼為 10000000
求10 -10 0 -128 127 的原碼、反碼、補碼
| 十進制 (字長8bit) | 原碼 | 反碼 | 補碼 |
|---|---|---|---|
| 10 | 00001010 | 00001010 | 00001010 |
| -10 | 10001010 | 11110101 | 11110110 |
| -1 | 1000 0001 | 1111 1110 | 1111 1111 |
| +0 | 00000000 | 00000000 | 00000000 |
| -0 | |||
| -128 | 無 | 無 | 10000000 |
| 127 | 01111111 | 01111111 | 01111111 |
| -127 | 11111111 | 10000000 | 10000001 |
+0和-0的補碼是一樣的。即 0的補碼只有一種表示,0的補碼是0000 0000,
# 四 輸出結果,解釋為什么是這樣的char c = 128;
printf("%d\n",c);
printf("%hhd\n",c);
printf("%hd\n",c);
printf("%hu\n",c);
4.1 格式輸出符
| 格式符號 | 意義 |
|---|---|
| %a | 浮點數、十六進制數字和p-記數法 (C99) |
| %A | 浮點數、十六進制數字和P-記數法 (C99) |
| %c | 一個字符 |
| %d | 有符號十進制整數 |
| %e | 浮點數、e-記數法 |
| %E | 浮點數、E-記數法 |
| %f | 浮點數,十進制記數法 |
| %g | 根據數值不同自動選擇%f或者%e。%e格式在指數小於-4或者大於等於精度時使用 |
| %G | 根據數值不同自動選擇%f或者%E。%E格式在指數小於-4或者大於等於精度時使用 |
| %i | 有符號十進制整數 (與%d相同) |
| %o | 無符號八進制整數 |
| %p | 指針(就是指地址) |
| %s | 字符串 |
| %u | 無符號十進制整數 |
| %x | 使用十六進制數字0f 的無符號十六進制整數 |
| %X | 使用十六進制數字0F的無符號十六進制整數 |
| %% | 打印一個百分號 |
| 修飾符 | 意義 | 示例 |
|---|---|---|
| h | 和整數轉換說明符一起使用,表示一個short int 或者 unsigned short int 類型數值。 | "%hd |
| hh | 和整數轉換說明符一起使用,表示一個signed char 或者unsigned char類型數值。 | "%hhd" |
| j | 和整數轉換說明符一起使用,表示一個intmax_t或uintmax_t值。 | "%jd" |
| l | 和整數說明符一起使用,表示一個long int 或者unsigned long int 類型值。 | "%8lu" |
| ll | 和整數說明符一起使用,表示一個long long int或 unsigned long long int 類型值 (C99)。 | "%lld" |
| L | 和浮點轉換說明符一起使用,表示一個long double值。 | "%8.4Le" |
| t | 和整數轉換說明符一起使用,表示一個ptrdiff_t值(與兩個指針之間的差相對應的類型) (C99) | "%td" |
| - | 項目是左對齊的,也就是說,會把項目打印在字段的左側開始處 | "%-20s" |
| + | 有符號的值若為正,則顯示帶加號的符號;若為負,則帶減號的符號。 | "%+3.2" |
| (空格) | 有符號的值若為正,則顯示時帶前導空格(但是不顯示符號);若為負,則帶減號符號。+標志會覆蓋空格標志。 | "% 3.2" |
| # | 使用轉換說明的可選形式。若為%o格式,則以0開始;若為%x和%X格式,則以0x或0X開始,對於所有的浮點形式,#保證了即使不限任何數字,也打印一個小數點字符。對於%g和%G格式,它防止尾隨零被刪除。 | "%#o" |
| 0 | 對於所有的數字格式,用前導零而不是用空格填充字段寬度。如果出現-標志或者指定了精度(對於整數)則忽略該標志。 | "%010d" |
char c = 128;
此處是將一個int賦值給一個char類型變量,進行隱式類型轉換.int型數值賦給char型變量時,只保留其最低8位,高位部分舍棄。
首先,整型128在一個字長為4個字節的的原碼為00000000 00000000 00000000 10000000,當把一個int類型賦值給一個有符號的char類型時,高位被舍棄。實際給c的是10000000,此時,被系統認為是一個負數,補碼為10000000,結合上面的分析,其值就是**-128**。
4.4 格式化輸出
char c = 128;
4.4.1 結論
先給出通過這次作業得出的一個不完全歸納法結論吧,也是我做出的解釋。最后會給出原碼驗證
1、正數的原碼的反碼、補碼是其本身,擴展時,高位補0;
2、負數擴展為有符號的高位補1,無符號的高位補0。
2、負數擴展時,高位補 1。格式化輸出無符號的數據時,機器碼即為原碼;格式化輸出有符號數據時,要先求其原碼,然后求得真值。
c 的機器碼為10000000 。
<background= brown>嗚嗚嗚嗚
4.4.2 輸出32位有符號int:
printf("%d\n",c);//默認的 int ,32位
將1000 0000 轉為有符號的32位機器碼:1111 1111 1111 1111 1111 1111 1000 0000
反碼:1111 1111 1111 1111 1111 1111 0111 1111
原碼:1000 0000 0000 0000 0000 0000 1000 0000
有符號,其值為:-128.
4.4.3 輸出8位有符號signed char:
printf("%hhd\n",c);//signed char, 8位
8位機器碼:1000 0000,
此機器碼沒有反碼和源碼,機器碼即為真值:-128.
4.4.4 輸出16位有符號 short int
printf("%hd\n",c);//short int,16 位
將1000 0000 轉為有符號的16位機器碼:1111 1111 1000 0000
反碼:1111 1111 0111 1111 原碼:1000 0000 1000 0000
有符號,其值為:-128.
4.4.5 輸出16位無符號 short int
printf("%hu\n",c);
將1000 0000 轉為16位機器碼:1111 1111 1000 0000
格式化輸出無符號十進制數據,此碼即為原碼。
原碼:1111 1111 1000 0000
做無符號運算,其值:65408
4.5 源碼
#include <iostream>
#include <bitset>
int main() {
using namespace std;
cout << "Hello Biter !" << endl;
char c = 128;
cout << "---------------- -" << int(c) << "----------------------- " << endl;
cout << "char 型 機器碼 = " << bitset<sizeof(char) * 8>(c) << endl;
cout << "int 型 機器碼 = " << bitset<sizeof(int) * 8>(c) << endl;
cout << "signed char 型 機器碼 = " << bitset<sizeof(signed char) * 8>(c) << endl;
cout << "short int 型 機器碼 = " << bitset<sizeof(short int) * 8>(c) << endl;
cout << "unsigned short int 型 機器碼 = " << bitset<sizeof(unsigned short int) * 8>(c) << endl;
cout << "char 二進制形式為 = " << bitset<sizeof(char) * 8>(c) << endl;
cout << "-------------------------------------------- " << endl;
// printf("將 char 直接 輸出 128 超范圍了 = %c\n", c);
// cout << "-------------------------------------------- " << endl;
printf("有符號的 int 輸出 = %d\n", c);
cout << "-------------------------------------------- " << endl;
printf("有符號的 signed char 輸出 = %hhd\n", c);//1000,0000
cout << "-------------------------------------------- " << endl;
printf("有符號的 short int 輸出= %hd\n", c);//0000,0000 1000,0000
cout << "-------------------------------------------- " << endl;
printf("無符號的 unsigned short int 輸出= %hu\n", c);// 1111,1111 1000,0000
cout << "-------------------------------------------- " << endl;
return 0;
}
