目錄
一、CPU的總線
1.1 32位與64位
32位CPU與64位CPU指的是什麼?
指的數據總線。
https://www.cnblogs.com/wtch519361/p/5278343.html
64位數據總線一次就能取出64bit的數據,8位數據總線的CPU一次只能取出8bit的數據
CPU總線,是PC系統中最快的總線,也是芯片組與主板的核心。這條總線主要由CPU使用,用來與高速緩存、主存和北橋(或MCH)之間傳送信息。
來自 <https://baike.baidu.com/item/CPU%E6%80%BB%E7%BA%BF/15739624?fr=aladdin>
1.2 總線類型
的數據總線DB(Data Bus)、地址總線AB(Address Bus)和控制總線CB(Control Bus),也統稱爲系統總線,即通常意義上所說的總線。
- 數據總線(Data Bus):在CPU與RAM之間來回傳送需要處理或是需要儲存的數據。
- 地址總線(Address Bus):用來指定在RAM(Random Access Memory)之中儲存的數據的地址。
- 控制總線(Control Bus):將微處理器控制單元(Control Unit)的信號,傳送到周邊設備。
- 擴展總線(Expansion Bus):外部設備和計算機主機進行數據通信的總線,例如ISA總線,PCI總線。
- 局部總線(Local Bus):取代更高速數據傳輸的擴展總線。
來自 <https://baike.baidu.com/item/%E6%80%BB%E7%BA%BF/108823>
1.3 32與64下的內存
除了long和void之外
Int,double,float的內存佔用沒有變化
具體內容:
http://www.unix.org/whitepapers/64bit.html
二、static與const
2.1 什麼是static?
靜態變量(Static Variable)在計算機編程領域指在程序執行前系統就爲之靜態分配(也即在運行時中不再改變分配情況)存儲空間的一類變量。
存儲類名 |
生命週期 |
作用域 |
extern |
靜態(程序結束後釋放) |
外部(整個程序) |
static |
靜態(程序結束後釋放) |
內部(僅翻譯單元,一般指單個源文件) |
auto,register |
函數調用(調用結束後釋放) |
無 |
定義全局變量前,加上關鍵字static,該變量就被定義成了一個靜態全局變量.
特點:
- 該變量在全局數據區分配內存.
- 初始化:如果不是顯示初始化,那麼將被隱式初始化爲0.
- 訪變量只在本文件可見,即應該爲定義之處開始到本文件結束.
程序在內存中一般分爲四個區域:
- 代碼區
- 全局數據區
- 堆區
- 棧區
一般程序由new產生的動態數據放在堆區,函數內部的自動變量放在棧區.自動變量一般會隨着函數的退出而釋放空間,靜態數據(即使是函數內部的靜態局部變量)都存放在全局數據區.因此它們並不會隨着函數的退出而釋放空間.
static int n;//定義靜態全局變量
改爲: int n;//定義全局變量
相關問題與理解
在C語言中,關於靜態變量的說法,正確的是( )。
- 靜態變量和常量的作用相同(錯誤,靜態變量表示內存區中固定位置的變量)
- 函數中的靜態變量,在函數退出後不被釋放(正確)
- 靜態變量只可以賦值一次,賦值後則不能改變(錯誤,靜態變量只是內存區中的位置不能改變)
- 靜態全局變量的作用域爲一個程序的所有源文件(錯誤,只是當前程序文件,想要擴展帶所有需要加extern修飾)
解析:
正確答案選第二個,靜態變量在函數退出後不會被釋放。因爲靜態變量是程序執行之前系統就靜態分配的變量了。
作用域爲當前文件,從定義/聲明位置到文件結尾。動態全局變量可以通過extern關鍵字在外部文件中使用,但靜態全局變量不可以在外部文件中使用。靜態全局變量相當於限制了動態全局變量的作用域。
靜態變量並不是說其就不能改變值,不能改變值的量叫常量。 其擁有的值是可變的 ,而且它會保持最新的值。說其靜態,是因爲它不會隨着函數的調用和退出而發生變化。即上次調用函數的時候,如果我們給靜態變量賦予某個值的話,下次函數調用時,這個值保持不變。
static在類內初始化還是類外初始化?
在C++中,類的靜態成員(static member)必須在類內聲明,在類外初始化,像下面這樣。
class A
{
private:
static int count; // 類內聲明
};
爲什麼?因爲靜態成員屬於整個類,而不屬於某個對象,如果在類內初始化,會導致每個對象都包含該靜態成員,這是矛盾的。
2.2 const
const是一個C語言(ANSI C)的關鍵字,具有着舉足輕重的地位。它限定一個變量不允許被改變,產生靜態作用。使用const在一定程度上可以提高程序的安全性和可靠性。另外,在觀看別人代碼的時候,清晰理解const所起的作用,對理解對方的程序也有一定幫助。
加了const修飾必須在一開始就初始化值,下面代碼編譯時候就會報錯,因爲沒有定義時就初始化值;
const int a;
a = 10;
下面代碼編譯的時候就會報錯,因爲const的值被更改了。
const int a=10;
cin >> a;
2.3 指針與const的關係
1)指針指向的變量的值不能變,指向可變
int x = 1;
int y = 2;
const int* px = &x;
int const* px = &x; //這兩句表達式一樣效果
px = &y; //正確,允許改變指向
*px = 3; //錯誤,不允許改變指針指向的變量的值
2)指針指向的變量的值可以改變,指向不可變
int x = 1;
int y = 2;
int* const px = &x;
px = &y; //錯誤,不允許改變指針指向
*px = 3; //正確,允許改變指針指向的變量的值
3)指針指向的變量的值不可變,指向不可變
int x = 1;
int y = 2;
const int* const px = &x;
int const* const px = &x;
px = &y; //錯誤,不允許改變指針指向
*px = 3; //錯誤,不允許改變指針指向的變量的值
四、虛函數|類|父類
以下描述正確的是( )?
- 虛函數是可以內聯的,可以減少函數調用的開銷,提高效率(錯誤,指針調用的時候,類不確定,所以虛函數不內聯)
- 類裏面可以同時存在函數名和參數都一樣的虛函數和靜態函數(靜態函數文件之外的函數可以與靜態函數重名,但是文件只能的函數不能與靜態函數重名,調用時候無法調用,存在二義性)
- 父類的析構函數是非虛的,但是子類的析構函數是虛的,delete子類對象指針會調用父類的析構函數
- 選項都不對
解析:正確選項爲C,刪除子類後,會調用子類的析構函數,子類的析構函數是虛函數,因此往上尋找父類,調用了父類的析構函數。
4.1 內聯
在計算機科學中,內聯函數(有時稱作在線函數或編譯時期展開函數)是一種編程語言結構,用來建議編譯器對一些特殊函數進行內聯擴展(有時稱作在線擴展)。
inline?Inline function。即可以理解爲編譯器直接講函數編譯到程序之中,而不是去調用。
4.2 虛函數
https://baike.baidu.com/item/%E8%99%9A%E5%87%BD%E6%95%B0/2912832?fr=aladdin
通過基類中virtual修飾的函數。在派生類中重新定義的成員函數。
用法格式爲:virtual 函數返回類型 函數名(參數表) {函數體};實現多態性,通過指向派生類的基類指針或引用,訪問派生類中同名覆蓋成員函數。
虛函數具有多態性。以不同的策略實現不同的方法。
簡單地說,那些被virtual關鍵字修飾的成員函數,就是虛函數。虛函數的作用,用專業術語來解釋就是實現多態性(Polymorphism),多態性是將接口與實現進行分離;用形象的語言來解釋就是實現以共同的方法,但因個體差異,而採用不同的策略。
虛函數實例
class A
{
public:
void print()
{
cout << "This is A" << endl;
}
};
class B : public A
{
public:
void print()
{
cout << "This is B" << endl;
}
};
int main()
{
A a;
B b;
A *ptr_a = &a;
B *ptr_b = &b;
a.print();
b.print();
ptr_a->print();
ptr_b->print();
int end; cin >> end;
return 0;
}
輸出:
This is A
This is B
This is A
This is B
如果將main函數改爲下面這樣:
int main()
{
//main2
A a;
B b;
A *p1 = &a;
A *p2 = &b;
p1->print();
p2->print();
a.print();
b.print();
int end; cin >> end;
return 0;
}
輸出就爲
This is A
This is A
This is A
This is B
爲什麼會這樣?直接用類就會調用當前類內的函數,用指針就調用父類的函數。
使用類的引用或指針調用虛函數時,無論虛函數什麼時間被調用,它都不能是內聯的(因爲虛函數的調用在運行時確定,這樣就會調用父類);
但是,使用類的對象調用虛函數時,無論虛函數什麼時間被調用,它都可以是內聯的(因爲在編譯時編譯器知道對象的確定類型)
爲了避免這個問題,所以就實現了虛函數,在每次繼承中都需要重新初始化。
class A
{
public:
virtual void print(){cout<<"This is A"<<endl;}
};
class B : public A
{
public:
void print(){cout<<"This is B"<<endl;}
};
這樣無論如何都能輸出:
This is A
This is B
This is A
This is B
解析:基類中函數定義爲虛函數,則派生類中函數自動定義爲虛函數,每次派生類中都需要重新定義。
4.3 虛函|內聯
https://blog.csdn.net/shuangshuang37278752/article/details/38875351
虛函數用於運行時多態或晚綁定或動態綁定,內聯函數用於提高程序的效率,內聯函數的思想:無論內聯函數什麼時間被調用,在編譯時,內聯函數的代碼段都可以在被替換或插入,當一些小函數在程序中被頻繁使用和調用時,內聯函數變得十分有用。
類內部定義的所有函數(虛函數除外)都被隱式或自動認爲是內聯的
使用類的引用或指針調用虛函數時,無論虛函數什麼時間被調用,它都不能是內聯的(因爲虛函數的調用在運行時確定);
但是,使用類的對象調用虛函數時,無論虛函數什麼時間被調用,它都可以是內聯的(因爲在編譯時編譯器知道對象的確定類型)
所以,虛函數不同條件下是否內聯不確定,但是是可以內聯的。類內調用可以內聯。
4.4 靜態函數
https://baike.baidu.com/item/%E9%9D%99%E6%80%81%E5%87%BD%E6%95%B0/5644260
全局函數:在類外聲明static函數的話,相當於一個全局函數,由於由於 static 的限制,它只能在文件所在的編譯單位內使用,不能在其它編譯單位內使用。
靜態函數:需要出現在類中,函數調用的結果不會訪問或者修改任何對象(非static)數據成員,這樣的成員聲明爲靜態成員函數比較好。它爲該類的公用變量,在第一次使用時被初始化,對於該類的所有對象來說,static成員變量只有一份。
靜態函數特點:
<1> 其他文件中可以定義相同名字的函數,不會發生衝突
<2> 靜態函數不能被其他文件所用。
內部函數又稱靜態函數。但此處“static”的含義不是指存儲方式,而是指對函數的作用域僅侷限於本文件。 使用內部函數的好處是:不同的人編寫不同的函數時,不用擔心自己定義的函數,是否會與其它文件中的函數同名,因爲同名也沒有關係。
4.5 幾種存儲方式
存儲說明符auto,register,extern,static,對應兩種存儲期:
自動存儲期和靜態存儲期。 auto和register對應自動存儲期。具有自動存儲期的變量在進入聲明該變量的程序塊時被建立,它在該程序塊活動時存在,退出該程序塊時撤銷。
關鍵字extern和static用來說明具有靜態存儲期的變量和函數。用static聲明的局部變量具有靜態存儲持續期(static storage duration),或靜態範圍(static extent)。雖然他的值在函數調用之間保持有效,但是其名字的可視性仍限制在其局部域內。靜態局部對象在程序執行到該對象的聲明處時被首次初始化。
五、sizeof(int)在什麼過程中出結果
編譯的階段,編譯,鏈接,運行?
它在編譯時候的運算符號.在Pascal 語言與C語言中,對 sizeof() 的處理都是在編譯階段進行。
解析:
https://www.cnblogs.com/huolong-blog/p/7587711.html
5.1 sizeof數據類型
short、int、long、float、double,不同操作平臺上結果不一樣
5.2 sizeof 結構體
結構體內需要字節對齊,以加快計算機的取數速度.所以,結構體以填充字節的形式來實現字節對齊.保證讓寬度爲2的基本數據類型(short等)都位於能被2整除的地址上,讓寬度爲4的基本數據類型(int等)都位於能被4整除的地址上. 空結構體(不含數據成員)的sizeof值爲1
1) 結構體變量的首地址能夠被其最寬基本類型成員的大小所整除。
2) 結構體的每個成員相對於結構體首地址的偏移量(offset)都是成員大小的整數倍,如有需要,編譯器會在成員之間加上填充字節(internal adding)。
3) 結構體的總大小爲結構體最寬基本類型成員大小的整數倍,如有需要,編譯器會在最末一個成員後加上填充字節(trailing padding)。
struct S1
{
char a;
int b;
};
sizeof(S1); //值爲8,字節對齊,在char之後會填充3個字節。
struct S2
{
int b;
char a;
};
sizeof(S2); //值爲8,字節對齊,在char之後會填充3個字節。
struct S3
{
};
sizeof(S3); //值爲1,空結構體也佔內存
5.3 sizeof union
是union中的內存的最大值。共用體和結構體都是由多個不同的數據類型成員組成, 但在任何同一時刻, 共用體只存放了一個被選中的成員。
例如:
union u
{
int a;
float b;
double c;
char d;
};
5.4 sizeof數組
返回數組的大小。
如果數組是char a[10],這種,sizeof返回10
但是如果是 char a[]="123",需要把結尾的\0 考慮上,返回值是4
對於函數的形參,則返回指針的大小。例如:
void func(char a[3])
{
int c = sizeof(a); //c = 4,因爲這裏a不在是數組類型,而是指針,相當於char *a。
}
void funcN(char b[])
{
int cN = sizeof(b); //cN = 4,理由同上。
}
sizeof(u); //值爲8
5.5 sizeof指針
指針爲地址總線的寬度。比如32位機中爲4, 64位機中,還是4嗎?
char *b = "helloworld";
char *c[10];
double *d;
int **e;
void(*pf)();
cout << "char *b = /"helloworld / " " << sizeof(b) << endl;//指針指向字符串,值爲4
cout << "char *b " << sizeof(*b) << endl; //指針指向字符,值爲1
cout << "double *d " << sizeof(d) << endl;//指針,值爲4
cout << "double *d " << sizeof(*d) << endl;//指針指向浮點數,值爲8
cout << "int **e " << sizeof(e) << endl;//指針指向指針,值爲4
cout << "char *c[10] " << sizeof(c) << endl;//指針數組,值爲40
cout << "void (*pf)(); " << sizeof(pf) << endl;//函數指針,值爲4
5.6 sizeof 函數
相當於求函數的返回值,不能求void函數的值。且函數不會被調用。
float FuncP(int a, float b)
{
return a + b;
}
int FuncNP()
{
return 3;
}
void Func()
{
return;
}
int main()
{
cout << sizeof(FuncP(3, 0.4)) << endl; //OK,值爲4,sizeof(FuncP(3,0.4))相當於sizeof(float)
cout << sizeof(FuncNP()) << endl; //OK,值爲4,sizeof(FuncNP())相當於sizeof(int)
/*cout<<sizeof(Func())<<endl; //error,sizeof不能對返回值爲空類型的函數求值*/
/*cout<<sizeof(FuncNP)<<endl; //error,sizeof不能對函數名求值*/
int end; cin >> end;
return 0;
}