clang 分四步編譯main.c


一 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

### 1.2.2 編譯階段,生成匯編
clang++ -S main.ii -o main.s 

### 1.2.3 匯編階段,生成目標文件
 clang++ -c main.s -o mian.o

### 1.2.4 連接階段 ```bash clang++ mian.o -o main ``` ![-c400](http://qiniu.binny.work/mweb/15679985192980.jpg)
### 1.2.5 執行
 ./main

## 1.3 四部曲之一步到胃 clang++在編譯的過程中,保存所有編譯過程中產生的文件

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

## 2.2 編譯 ``` armv7a-linux-androideabi29-clang++ -S main.ii -o main.s ``` ![-c400](http://qiniu.binny.work/mweb/15680009962550.jpg)
## 2.3 匯編
armv7a-linux-androideabi29-clang++ -c main.s -o mian.o

## 2.4 連接
armv7a-linux-androideabi29-clang++ mian.o -o main

# 3 原碼、反碼、補碼 ## 3.1 知識點補充 在計算機內部,所有信息都是用二進制數串的形式表示的。整數通常都有正負之分,計算機中的整數分為無符號的和帶符號的。無符號的整數用來表示0和正整數,即自然數;帶符號的正數可以表示所有的整數。

由於計算機中符號和數字一樣,都必須用二進制數串來表示,因此,正負號也必須用0、1來表示。通常我們用最高的有效位來 表示數的符號(當用8位來表示一個整數時,第8位即為最高有效位,當用16位來表示一個整數時,第16位即為最高有效位。)0表示正號、1表示負號。

這種正負號數字化(0表示正號、1表示負號)的機內表示形式就稱為機器碼或者機器數,而相應的機器外部用正負號表示的數稱為真值。將一個真值表示成二進制字串的機器數的過程就稱為編碼

無符號數沒有原碼、反碼和補碼一說。只有帶符號數才存在不同的編碼方式。帶符號整數有原碼、反碼、補碼等幾種編碼方式。

原碼即直接將真值轉換為其相應的二進制形式,而反碼和補碼是對原碼進行某種轉換編碼方式。

正整數原碼反碼補碼都一樣。

負數的反碼是對原碼的除符號位外的其他位進行取反后的結果(取反即如果該位為0則變為1,而該位為1則變為0的操作)。而補碼是先求原碼的反碼,然后在反碼的末尾位加1 后得到的結果,即補碼是反碼+1。

IBM-PC中帶符號整數都采用補碼形式表示。

注意,只是帶符號的整數采用補碼存儲表示的,浮點數另有其存儲方式。

  1. 正數的補碼是其本身
  2. 負數的反碼,符號位不變,其余的按位取反
  3. 負數的補碼,反碼加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 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 10000000 11111111 00000000
-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的無符號十六進制整數
%% 打印一個百分號
## 4.2 格式輸出其修飾符
修飾符 意義 示例
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"
## 4.3 機器碼求解
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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM