《C++文章匯總》
上一篇介紹了引用和匯編《03-Reference、匯編》,本文介紹匯編其他指令、引用和Const。
1.x64匯編要點總結
?mov dest, src
將src的內容賦值給dest,類似于dest = src
?[ 地址值 ]
中括號[ ]里面放的都是內存地址
?word是2字節,dword是4字節(double word),qword是8字節(quad word) ?call 函數地址
調用函數
?lea dest, [ 地址值 ]
將地址值賦值給dest,類似于dest = 地址值
?ret 其實內部也包含jump功能
函數返回
?xor op1, op2
將op1和op2異或的結果賦值給op1,類似于op1 = op1 ^ op2
?add op1, op2
類似于op1 = op1 + op2
?sub op1, op2
類似于op1 = op1 - op2
?inc op
自增,類似于op = op + 1
?dec op
自減,類似于op = op – 1
?jmp 內存地址
跳轉到某個內存地址去執行代碼 ?j開頭的一般都是跳轉,大多數是帶條件的跳轉,一般跟test、cmp等指令配合使用
? 權威參考:Intel白皮書 ?https://software.intel.com/en-us/articles/intel-sdm
函數的返回值放在eax中
2.Jump Condition Code
01、 | JE, JZ | 結果為零則跳轉(相等時跳轉) | ZF=1 | ||||||
---|---|---|---|---|---|---|---|---|---|
equal | zero | ||||||||
02、 | JNE, JNZ | 結果不為零則跳轉(不相等時跳轉) | ZF=0 | ||||||
not equal | not zero | ||||||||
03、 | JS | 結果為負則跳轉 | SF=1 | ||||||
sign(有符號\有負號) | |||||||||
04、 | JNS | 結果為非負則跳轉 | SF=0 | ||||||
not sign(無符號\無負號) | |||||||||
05、 | JP, JPE | 結果中1的個數為偶數則跳轉 | PF=1 | ||||||
parity even | |||||||||
06、 | JNP, JPO | 結果中1的個數為偶數則跳轉 | PF=0 | ||||||
parity odd | |||||||||
07、 | JO | 結果溢出了則跳轉 | OF=1 | ||||||
overflow | |||||||||
08、 | JNO | 結果沒有溢出則跳轉 | OF=0 | ||||||
not overflow | |||||||||
09、 | JB, JNAE | 小于則跳轉 (無符號數) | CF=1 | ||||||
below | not above equal | < | |||||||
10、 | JNB, JAE | 大于等于則跳轉 (無符號數) | CF=0 | ||||||
not below | above equal | >= | |||||||
11、 | JBE, JNA | 小于等于則跳轉 (無符號數) | CF=1 or ZF=1 | ||||||
below equal | not above | <= | |||||||
12、 | JNBE, JA | 大于則跳轉(無符號數) | CF=0 and ZF=0 | ||||||
not below equal | above | > | |||||||
13、 | JL, JNGE | 小于則跳轉 (有符號數) | SF≠ OF | ||||||
little | not great equal | < | |||||||
14、 | JNL, JGE | 大于等于則跳轉 (有符號數) | SF=OF | ||||||
not little | great equal | >= | |||||||
15、 | JLE, JNG | 小于等于則跳轉 (有符號數) | ZF=1 or SF≠ OF | ||||||
little equal | not great | <= | |||||||
16、 | JNLE, JG | 大于則跳轉(有符號數) | ZF=0 and SF=OF | ||||||
not little equal | great | > |
CPU架構決定無法mov 內存到內存,要通過寄存器來進行運算中轉
mov帶單位,取數據,取多少個字節,lea不帶單位,lea賦值內存地址,指針牽扯到取地址值,標記是lea eax,[ebp-0Ch],不能寫成mov eax ebp-0Ch,mov指令不能做運算,但可以
sub ebp,0CH//會改掉ebp的值
mov eax,ebp
指針變量賦值
//int age = 3;
//ebp-0Ch是age的地址值
008519C2 mov dword ptr [ebp-0Ch],3
//eax == ebp-0Ch,存放著age的地址值
008519C9 lea eax,[ebp-0Ch]
//ebp-18h是指針變量p的地址值
//將age的地址值存放到指針變量p所在的存儲空間
//int *p = &age;
008519CC mov dword ptr [ebp-18h],eax
//*p = 5
//將age的地址值存放到eax
008519CF mov eax,dword ptr [ebp-18h]
//age = 5
008519D2 mov dword ptr [eax],5
指針變量的地址值,另外一個變量的地址值賦值給指針變量去存儲
lea eax,[ebp-0Ch]
mov dword ptr [ebp-18h],eax
如下圖:引用的內存匯編和指針變量一模一樣
3.引用
A.結構體引用
#include <iostream>
using namespace std;
struct Date {
int year;
int month;
int day;
};
int main(int argc, const char * argv[]) {
Date d = {2011,1,5};
Date &ref = d;
ref.year = 2014;
getchar();
return 0;
}
B.指針引用
int main(int argc, const char * argv[]) {
int age = 10;
int *p = &age;
int *&ref = p;
*ref = 30;
int height = 30;
ref = &height;
getchar();
return 0;
}
C.數組引用
int main(int argc, const char * argv[]) {
int array[] = {1,2,3};
int (&arr)[3] = array;
int *p;
//指針數組
int *a[3] = {p,p,p};
//數組指針:指向數組的指針
int (*ar)[3] = &array;
getchar();
return 0;
}
不存在引用的引用,指向引用的指針,引用數組
D.常引用(Const Reference)
? 引用可以被const修飾,這樣就無法通過引用修改數據了,可以稱為常引用
int main(int argc, const char * argv[]) {
int age = 10;
const int &ref = age;
const int *p = &age;
// ref = 30;
// *p = 30;
cout << ref << endl;
cout << *p << endl;
getchar();
return 0;
}
//輸出
10
10
? const、指針、引用
int main(int argc, const char * argv[]) {
int height = 20;
int age = 10;
//ref1不能修改指向,但是可以通過ref1間接修改指向的變量的值
// int& const ref1 = age;const可以直接去掉,引用本來就不能修改指向
// ref1 = 30;不報錯
//ref2不能修改指向,不可以通過ref2間接修改指向的變量的值
int const &ref2 = age;
// ref2 = 30;報錯
//p1不能修改指向,可以利用p1間接修改指向的變量
int * const p1 = &age;
*p1 = 40;
//p2可以修改指向,不可以利用p2間接修改指向的變量
int const *p2 = &age;
// *p2 = 50;報錯
p2 = &height;
getchar();
return 0;
}
const必須寫在&符號的左邊,才能算是常引用
? const引用的特點
可以指向臨時數據(常量、表達式、函數返回值等)
可以指向不同類型的數據
作為函數參數時(此規則也適用于const指針)
? 可以接受const和非const實參(非const引用,只能接受非const實參)
? 可以跟非const引用構成重載
int func(){
return 8;
}
int sum(int &v1,int &v2){
cout << "sum(int &v1,int &v2)" << endl;
return v1 + v2;
}
int sum(const int &v1,const int &v2){
cout << "sum(const int &v1,const int &v2)" << endl;
return v1 + v2;
}
int main(int argc, const char * argv[]) {
//非const實參
int c = 10;
int d = 20;
sum(c, d);
//const實參
const int e = 10;
const int f = 20;
sum(e, f);
sum(10, 20);
int a = 1;
int b = 2;
const int &ref = 30;
const int &ref0 = a + b;
const int &ref1 = func();
int age = 10;
const double &ref3 = age;
getchar();
return 0;
}
//輸出
sum(int &v1,int &v2)
sum(const int &v1,const int &v2)
sum(const int &v1,const int &v2)
? 當常引用指向了不同類型的數據時,會產生臨時變量,即引用指向的并不是初始化時的那個變量
I.常引用ref指向了相同類型數據
int main() {
int age = 10;
const int &ref = age;
age = 30;
cout << "age is " << age << endl;
cout << "ref is " << ref << endl;
getchar();
return 0;
}
//輸出
age is 30
ref is 30
查看匯編,age的值變為了30,ref的值也變為了30
//int age = 10;
mov dword ptr [ebp-0Ch],0Ah
//age的內存地址給到eax
lea eax,[ebp-0Ch]
//[ebp-18h]這段內存空間存放age的內存空間[ebp-0Ch]
mov dword ptr [ebp-18h],eax
//30賦值給[ebp-0Ch]內存地址
mov dword ptr [ebp-0Ch],1Eh
II.常應用ref指向了不同類型數據
#include <iostream>
using namespace std;
int main() {
/*
int age = 10;
const int &ref = age;
age = 30;
cout << "age is " << age << endl;
cout << "ref is " << ref << endl;
*/
int age = 10;
const long &ref = age;
age = 30;
cout << "age is " << age << endl;
cout << "ref is " << ref << endl;
getchar();
return 0;
}
//輸出
age is 30
ref is 10
查看匯編,age的值變為了30,而引用ref沒有變,在一塊新的內存空間中存儲
//int age = 10;
mov dword ptr [ebp-0Ch],0Ah
//將10取出來給eax
mov eax,dword ptr [ebp-0Ch]
//將eax給到[ebp-24h]這段內存空間,相當于temp
mov dword ptr [ebp-24h],eax
//將[ebp-24h]這段內存空間 temp給到ecx
lea ecx,[ebp-24h]
//將ecx里面的內存地址的值取出來給到[ebp-18h]
mov dword ptr [ebp-18h],ecx
//將30給到[ebp-0Ch],age就變化了,ref沒有變化
mov dword ptr [ebp-0Ch],1Eh
E.不同的編程語言轉成的匯編是一樣的嗎?
Java,C++,OC,Swift寫代碼--->匯編機器碼取決于CPU架構(X86,ARM)。