程序分為三份
創(chuàng)新互聯(lián)是一家專注于成都網(wǎng)站建設(shè)、成都做網(wǎng)站與策劃設(shè)計,澤普網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)10多年,網(wǎng)設(shè)計領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:澤普等地區(qū)。澤普做網(wǎng)站價格咨詢:028-86922220不要#include源代碼文件,否則會多重聲明
1.1 頭文件 內(nèi)容不要把函數(shù)定義或者變量聲明放到頭文件中
頭文件中通常包含:
#define
或者const
定義的符號常量結(jié)構(gòu)聲明,類聲明,模板聲明可以放在頭文件中,因?yàn)樗鼈儾粍?chuàng)建變量,
而是指示編譯器生成和創(chuàng)建。
const數(shù)據(jù)和內(nèi)聯(lián)函數(shù)有特殊的鏈接屬性,所以可以放在頭文件中。
可以將成員放在名稱空間中
引用方式尖括號:編譯器在存儲標(biāo)準(zhǔn)頭文件的主機(jī)系統(tǒng)的文件系統(tǒng)中查找
雙引號:首先查找當(dāng)前的工作目錄和源代碼目錄,如果沒找到,在標(biāo)準(zhǔn)位置找
同一個文件只能包含同一個頭文件一次,否則編譯錯誤
#ifndef COORDIN_H_
#define COORDIN_H_
//頭文件內(nèi)容
#endif
1.2 編譯流程以UNIX執(zhí)行C為例
(71條消息) C+±-名字修飾_Emma-Zhang的博客-博客_c++名稱修飾
在C/C++中,一個程序要運(yùn)行起來,需要經(jīng)歷以下幾個階段:預(yù)處理、編譯、匯編、鏈接。
名字修飾(Name Mangling)是一種在編譯過程中,將函數(shù)、變量的名稱重新改編的機(jī)制,簡單來說就是編譯器為了區(qū)分各個函數(shù),將函數(shù)通過一定算法,重新修飾為一個全局唯一的名稱。
兩個編譯器對同一個函數(shù)可能生成不同的修飾名稱,所以不同的名稱會使鏈接器無法將編譯器生成的函數(shù)調(diào)用與另一個編譯器生成的函數(shù)定義匹配。
因此在鏈接編譯模塊時,請確保所有對象文件或庫都是由同一個編譯器生成的。
2 存儲持續(xù)性,作用域,鏈接性C++存儲方式是通過存儲持續(xù)性,作用域和鏈接性來描述的
2.1 存儲持續(xù)性數(shù)據(jù)保存在內(nèi)存中的時間
thread_local
聲明的變量。作用域(scope)描述名稱在文件的多大范圍可見。
局部作用域?yàn)榫植恐辉诙x的代碼塊可用。
全局作用域?yàn)槿郑ㄒ步形募饔糜颍┑淖兞吭诙x位置到文件結(jié)尾都可用。
變量作用域作用域可以是類或者名稱空間(包括全局),但不能是局部的,不然只對自己可見。
2.3 鏈接性鏈接性(linkage)描述了名稱如何在不同單元之間共享。
鏈接性為外部的名稱可以在文件間共享
鏈接性為內(nèi)部的名稱只能由一個文件中的函數(shù)共享
自動變量的名稱沒有鏈接性,因?yàn)樗鼈儾荒芄蚕怼?/p>3 變量的存儲方式
這里介紹引入名稱空間之前的情況
3.1 自動存儲持續(xù)性函數(shù)中聲明的函數(shù)參數(shù)和變量:
存儲持續(xù)性:自動
作用域:局部,從聲明位置到代碼塊結(jié)束
鏈接性:無
分配內(nèi)存的時機(jī):執(zhí)行到該代碼塊
同名自動變量當(dāng)兩個同名的變量一個位于外部,一個位于內(nèi)部時,內(nèi)部的將被解釋為局部代碼塊變量,為新定義。新定義隱藏了以前的定義,內(nèi)部代碼塊中新定義可見,舊定義不可見。
auto關(guān)鍵字C++11開始,auto用于自動類型推斷,但是在C中或者C++11之前,auto用于顯式地指出變量為自動存儲。
register關(guān)鍵字寄存器變量:register關(guān)鍵字是由C語言引入的,建議編譯器使用CPU寄存器來存儲自動變量,旨在提高訪問變量的速度
在C++11以前,register表明變量用的很多,編譯器可以對其做特殊處理。
C++11后只限于指出變量是自動的
3.2 靜態(tài)持續(xù)變量保留關(guān)鍵字的重要原因是避免使用了該關(guān)鍵字的現(xiàn)有代碼非法
靜態(tài)變量的數(shù)目在程序運(yùn)行期間不變,所以不需要用棧管理,只需要固定內(nèi)存分配,在程序執(zhí)行期間一直存在。
如果沒有初始化,編譯器將靜態(tài)變量設(shè)為0,稱為零初始化的(zero-initialized)
靜態(tài)存儲持續(xù)性變量有三種鏈接性:
int global=1000; //外部鏈接性靜態(tài)變量
static int one_file=50; //內(nèi)部鏈接性靜態(tài)變量
int main()
{...}
void func1()
{
static int count =0;//無鏈接性靜態(tài)變量
}
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-zuPN0hEO-1672942524360)(C:/Users/l/AppData/Roaming/Typora/typora-user-images/image-20221230205803189.png)]
關(guān)鍵字重載代碼塊內(nèi)static指存儲持續(xù)性,代碼塊外部static表示內(nèi)部鏈接性,這種關(guān)鍵詞含義取決于上下文的現(xiàn)象叫關(guān)鍵詞重載
靜態(tài)變量初始化靜態(tài)變量都必須先零初始化,如果顯式初始化了,那就有兩種初始化方式
要調(diào)用函數(shù),必須等到函數(shù)被鏈接且程序執(zhí)行時,是動態(tài)初始化。
但是常量初始化可以使用sizeof()和C++11關(guān)鍵字constexpr
,這增加了創(chuàng)建常量表達(dá)式的方式。
外部鏈接性的靜態(tài)持續(xù)性的變量
鏈接性為外部的變量稱為**(常規(guī))外部變量**,又稱為全局變量(相對于局部的自動變量),每個使用外部變量的文件必須聲明它。
單定義規(guī)則C++有單定義規(guī)則:(one definition rule,ODR)變量只能有一次定義。
C++提供兩種變量聲明:
extern
,且不能進(jìn)行初始化要在多個文件使用外部變量,需要在其他文件用extern
聲明。
定義與全局變量同名的局部變量后,局部變量將隱藏全局變量。
作用域解析運(yùn)算符C++提供作用域解析運(yùn)算符::
,放在變量名前,表示使用變量的全局版本
指內(nèi)部鏈接性的靜態(tài)持續(xù)性的變量
static限定符用于作用域?yàn)檎麄€文件的變量,該變量的鏈接性變?yōu)閮?nèi)部,稱為靜態(tài)外部變量
如果在文件中定義了一個靜態(tài)外部變量,與另一個文件的常規(guī)外部變量重名,則該文件中隱藏常規(guī)外部變量
用處:在同一個文件中的多個函數(shù)間共享數(shù)據(jù)
3.5 無鏈接的靜態(tài)變量指無鏈接性的靜態(tài)持續(xù)性的變量
函數(shù)內(nèi)的靜態(tài)變量只在程序開始運(yùn)行時被設(shè)置為0,當(dāng)再次調(diào)用函數(shù)時不會再次初始化
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-TcGnLnFB-1672942524361)(C:/Users/l/AppData/Roaming/Typora/typora-user-images/image-20221231162728980.png)]
int a=1000; //外部鏈接性靜態(tài)變量
static int b=50; //內(nèi)部鏈接性靜態(tài)變量
extern int c=20;
int main()
{...}
void func1()
{
static int g =0;//無鏈接性靜態(tài)變量
}
4 存儲說明符和cv-限定符存儲說明符(storage class specifier)有
cv-限定符(cv-qualifier)(cv取兩個單詞的首字母)有
作用域?yàn)檎麄€文件時,表示內(nèi)部鏈接性;局部聲明中,表示存儲持續(xù)性。
C++中static作用和使用方法
extern關(guān)鍵字引用聲明,聲明引用在其他地方被定義的變量,見”外部變量“。
thread_local關(guān)鍵字同一個聲明中不能使用多個說明符,除了thread_local
,可以和static
和extern
結(jié)合使用
指出變量的持續(xù)性與其所屬線程的持續(xù)性相同,thread_local
之于線程,猶如常規(guī)靜態(tài)變量之于整個程序。
內(nèi)存被初始化后,程序不能對它進(jìn)行修改。
const char * const months[12]=
{
"January","February",···
};
第一個const防止字符串被修改,第二個const確保數(shù)組每個指針始終指向它最初指向的字符串。
const全局變量C++中,const全局變量的鏈接性為內(nèi)部的,如同使用了static。這樣每個文件都有頭文件中定義的const變量但是不會因?yàn)閱味x規(guī)則而沖突。
如果希望定義在函數(shù)外部的const變量的鏈接性為外部的,需要用extern關(guān)鍵字來覆蓋。而且必須在所有使用變量的文件中用extern聲明。
不管如何,只有一個文件能初始化。
//使用const
//1.cpp
extern const int states=50;
//2.cpp
extern const int states;
//不使用const
//1.cpp
int states=50;
//2.cpp
extern int states;
代碼塊中的const作用域?yàn)榇a塊
volatile關(guān)鍵字volatile:不穩(wěn)定的
關(guān)鍵詞volatile
表明:即使程序代碼沒有對內(nèi)存單元進(jìn)行修改,值也可能變化。
使用場景:
volatile
則編譯器不會進(jìn)行這種優(yōu)化mutable:會變的,可變的
關(guān)鍵詞mutable
指出:即使結(jié)構(gòu)/類為const,某個成員也可以被修改
struct data
{
char name[30];
mutable int accesses;
};
const data a ={"hi",0};
strcpy(a.name,"hello"); //不允許
a.accesses++; //允許
5 其他鏈接性
5.1 函數(shù)的鏈接性
存儲持續(xù)性C++和C都不允許在一個函數(shù)中定義另一個函數(shù),因此所有函數(shù)的存儲持續(xù)性都自動為靜態(tài)的,在程序執(zhí)行期間一直存在。
默認(rèn)鏈接性extern
,表示函數(shù)的定義在另一個文件static
可以將函數(shù)的鏈接性設(shè)為內(nèi)部,必須在原型和函數(shù)定義中使用該關(guān)鍵詞如果定義了一個與庫函數(shù)同名的函數(shù),編譯器將使用程序員定義的版本,而不是庫函數(shù),但是C++保留了標(biāo)準(zhǔn)庫函數(shù)的名稱。
5.2 語言鏈接性C語言中一個名稱只對應(yīng)一個函數(shù),C++同一個名稱可能對應(yīng)多個函數(shù),必須翻譯為不同的符號名稱,因此通過C++語言鏈接來實(shí)現(xiàn)。
C++語言鏈接:為函數(shù)名稱翻譯成不同的符號名稱,執(zhí)行名稱矯正或者名稱修飾。
涉及鏈接程序?qū)瘮?shù)的處理。見書262
6 動態(tài)內(nèi)存動態(tài)內(nèi)存由new和delete控制,而不是由作用域和鏈接性規(guī)則控制。可以在一個函數(shù)中分配,另一個函數(shù)中釋放。
存儲方案不適用于動態(tài)內(nèi)存,但適用于用來跟蹤動態(tài)內(nèi)存的自動和靜態(tài)指針變量。
float * p_fees =new float [20];
由new分配的動態(tài)內(nèi)存會一直保留,但是聲明的語句塊執(zhí)行完后,指針將消失,所以必須在代碼結(jié)束后返回地址,不然無法使用該內(nèi)存。
6.1 分配內(nèi)存int *pi=new int (6);
double *pd=new double (99.99);
//列表初始化
struct where {double x;double y;double z;};
where *one =new where {2.5,5.3,7.2}//C++11 對結(jié)構(gòu) 列表初始化
int * ar =new int [4] {2,4,6,7};//C++11 對數(shù)組 列表初始化
double *pd =new double {99.99};//C++11 對單值變量 列表初始化
分配函數(shù) new()void * operator new(std::size_t);
void * operator new[] (std::size_t);
使用運(yùn)算符重載。size_t是個typedef,對應(yīng)合適的整型
int * pi=new int;
被轉(zhuǎn)化為int * pi=new(sizeof(int))
分配函數(shù)和釋放函數(shù)是可替換的,可以為new和delete提供替換函數(shù)
分配失敗最初返回空指針,現(xiàn)在引發(fā)異常std::bad_alloc
程序結(jié)束后,new分配的內(nèi)存通常將被釋放,但請求大型內(nèi)存塊將導(dǎo)致代碼塊在程序結(jié)束不會被自動釋放
這時需要delete
釋放函數(shù)delete()void operator delete(void *);
void operator delete[](void *);
具體參考書P264
new運(yùn)算符處理在堆中找內(nèi)存塊還有一種變體,讓程序員可以指定要使用的位置,這樣可以處理通過特定地址進(jìn)行訪問的硬件或者在特定位置創(chuàng)建對象。
與常規(guī)new的區(qū)別常規(guī)new調(diào)用一個接受一個參數(shù)的new()函數(shù),而定位new調(diào)用的接受兩個參數(shù)
頭函數(shù):#include
使用定位new,變量后面可以有方括號也可以沒有
可以用于結(jié)構(gòu)和對象等
用法可以用靜態(tài)數(shù)組為定位new提供內(nèi)存空間
char buffer[500];
int main(){
int *p;
p=new (buffer) int[20];
}
工作原理默認(rèn)定位new函數(shù):返回傳遞給定位new運(yùn)算符的地址,并強(qiáng)制轉(zhuǎn)化為void *,這樣可以賦給任何指針類型
C++允許重載定位new函數(shù),但定位new是不可替換的
7 名稱空間為了防止兩個庫的名稱沖突,需要用名稱空間控制名稱的作用域
7.1 傳統(tǒng)的名稱空間 聲明區(qū)域|潛在作用域|作用域聲明區(qū)域:可以在其中進(jìn)行聲明的區(qū)域
潛在作用域:變量的潛在作用域從聲明點(diǎn)開始,到其聲明區(qū)域的結(jié)尾,潛在作用域比聲明區(qū)域小
作用域:變量對程序可見的范圍被稱為作用域
7.2 名稱空間命名的名稱空間
特征用作用域解析運(yùn)算符來使用名稱空間來限定名稱,未被修飾的叫未限定的名稱,包含名稱空間的名稱叫限定的名稱
7.3 using聲明using
聲明由被限定的名稱和前面的關(guān)鍵字using組成
using聲明會把特定的名稱添加到所屬的聲明區(qū)域內(nèi)
在函數(shù)中添加到局部聲明區(qū)域,覆蓋同名的全局變量;在函數(shù)外添加到全局名稱空間中
using聲明對于函數(shù)如果只給出了
namespace Jill
{
double fetch;
}
char fetch;
int main()
{
using Jill::fetch;
//double fetch; //錯的,已經(jīng)定義了fetch
cin>>fetch; //讀取Jill::fetch
cin>>::fetch; //讀取全局的fetch
}
7.4 using 編譯指令using聲明使得一個名稱可用,而using編譯指令使得所有的名稱都可用
using編譯指令由名稱空間名和using namespace
組成
全局聲明區(qū)域內(nèi)使用using namespace,使得名稱空間的全部名稱全局可用
函數(shù)中使用using編譯指令,則函數(shù)中可用
函數(shù)重載與usingC++using聲明和using指示_蓮?fù)薜牟┛?博客_using
兩者比較同:using編譯指令和using聲明存在可能的二義性,比如兩個名稱空間都定義了同樣的名稱,這時候編譯器不允許同時使用這兩個using聲明
異:using聲明與聲明類似,如果函數(shù)中已經(jīng)聲明,則不能用其導(dǎo)入相同的名稱
using編譯指令類似于作用域解析運(yùn)算符,讓函數(shù)內(nèi)部將其視為函數(shù)之外聲明的。即如果已經(jīng)有局部聲明,則名稱空間名被隱藏,但是仍然可以通過::變量名
取得全局的對應(yīng)變量,名稱空間::變量名
取得名稱空間的對應(yīng)變量
一般認(rèn)為using聲明更加安全,因?yàn)榫幾g指令如果重名,編譯器不會警告,而且使用名稱空間的變量也沒有明確特征和說明
using namespace std; //減少這么使用
int x; //用法1
std::cin>>x;
using std::cin; //用法2
int x;
cin>>x;
名稱空間的嵌套對于:
namespace elements
{
namespace fire
{
int flame;
}
}
使用:using namespace elements::fire
再例如:
namespace myth
{
using Jill::fetch; //Jill名稱空間內(nèi)的fetch變量
using namespace elements;
}
直接使用:myth::fetch
訪問即可
using編譯指令可傳遞,使用using namespace myth;
相當(dāng)于同時還使用了using namespace elements;
namespace m=myth;
namespace MEF=myth::elements::fire;
using MEF::flame;
未命名的存儲空間相等于鏈接性為內(nèi)部的靜態(tài)變量
namespace
{
int counts
}
//等于
static int counts2;
int main()
{...}
8 C++的內(nèi)存分區(qū)編譯器使用前三塊獨(dú)立內(nèi)存,程序在此基礎(chǔ)上還需要代碼區(qū):
數(shù)據(jù)區(qū)包括:堆,棧,靜態(tài)存儲區(qū)。
靜態(tài)存儲區(qū)包括:常量區(qū)(靜態(tài)常量區(qū)),全局區(qū)(全局變量區(qū))和靜態(tài)變量區(qū)(靜態(tài)區(qū))。
常量區(qū)包括:字符串常量區(qū)和常變量區(qū)。
代碼區(qū):存放程序編譯后的二進(jìn)制代碼,不可尋址區(qū)。
對于大型編程項(xiàng)目的管理:
當(dāng)然,一個文件的程序不受此限制
10 留給讀者的問題感謝看到這里,寫到凌晨兩點(diǎn),麻煩點(diǎn)下贊謝謝
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
當(dāng)前標(biāo)題:【格蕾讀C++PrimerPlus】第九章內(nèi)存模型和名稱空間-創(chuàng)新互聯(lián)
網(wǎng)頁鏈接:http://vcdvsql.cn/article30/jgdpo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號、微信小程序、標(biāo)簽優(yōu)化、網(wǎng)頁設(shè)計公司、網(wǎng)站設(shè)計、網(wǎng)站營銷
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容