一些關鍵字的使用解析

2021-08-11 11:20:22 字數 4454 閱讀 1529

一,前言

平時在使用時,我們或多或少都會有疑惑,乙個型別前加乙個const到底有什麼作用呢?類似的還有static,volatile,extern,extern 「c」等,今天我便會把自己總結的知識,記錄在這裡。

二,主要內容

2.1 const與不加const

關鍵字const並不能把變數變成常量,在乙個符號前加上const限定符只是表明這個符號不能被賦值,也就是說它的值對於這個符號來說是唯讀的,但它並不能防止通過程式的內部(甚至是外部)的方法來修改這個值。

const最有用之處就是用它來限定函式的形參,這樣該函式就不會修改實參指標所指的資料。

以上內容來自《c專家程式設計》

首先來看個例子:

#pragma once

#include

/*const 與 非const的使用

*/void test()

這個例子十分簡單,我們聲名並定義了乙個int型的const變數a,然後試圖去修改a的值,但發現此時編譯器已經提示「表示式必須是可修改的左值」,此時有同學可能會疑惑,什麼是左值?相應的什麼是右值呢?

所謂的左值是指賦值運算子「=」左邊的數,它代表乙個位址;

而右值便是指「=」右邊的數,它往往代表乙個值。

當我們使用賦值運算子時,往往是把右值賦給左值所代表的位址空間裡,而這個位址,在程式執行時會被自動分配。

那麼a為什麼不能被修改呢?正如上面那段話所說,被const修飾,則a當前的屬性為唯讀的(read-only),意味著你不能對它進行賦值,那麼a就是乙個常量了?請看下面的**:

void test()

執行之後,我們發現,雖然通過強制型別轉換,我們得到到a的位址,並通過指向a的指標b修改了a的值,但輸出的結果,依舊是a=3,*b=4,這是為什麼呢?

此時便正式引出了「volatile」關鍵字,該關鍵字的中文意思是:多變的,不穩定的。正如它的字面意思,它修飾乙個變數,是為了告訴編譯器這個變數是經常變化的,讓編譯器每次都去相應的位址取值。原來啊,編譯器為了優化程式的執行效率,它把const變數a的值存入了暫存器中,這樣每次取a的值時就不用通過位址去取相應的變數,直接使用了暫存器裡的值,這也就是為什麼我們修改了a的值,但列印出來的依舊是暫存器裡面沒有發生變化的。然後再看改進的版本:

void test()

結果:

注意:在c++裡面,如果乙個類的成員用mutable關鍵字修飾時,則它在const的成員函式裡可以發生改變,不會發生錯誤。

2.2 指標與const

在日常使用中,我們通常會遇到下面幾種形式:

int a=3;

1, int const *b=&a;

2,const int *b=&a;

3, int* const b=&a;

4,const int* const b=&a;

其中1,2是相同的形式,它們都定義了指標b並指向a的位址,const修飾的是*b,即b所指向的那個int變數的值是常量,此時b又稱為指標常量,「指標」為形容詞,而「常量」是名詞

第三個,稱為常量指標,const離指標b更近,它表示指標b所指向的位址是不能被改變的。

第四個則表示指標b所指向的位址不能被修改,而且那個位址所存放的那個整型的值也不能被修改,b又被稱為常指標。

我們知道const修飾的變數需要在定義的時候被初始化,但由於1,2中const所修飾的是指標變數,所以const修飾的是指向的那個整型的值,所以對於指標b來說,並不需要使用位址對指標進行初始化,而3,4由於修飾的是指標,所以指標需要顯式的用位址來進行初始化。

2.3 char*與const char*

首先請看**:

void test()

我們定義了a和b兩個指標,其中b是被const修飾的,首先看注釋1,我們讓b=a,此時程式並沒有什麼異常,但當我們把 b給a賦值時便出現了錯誤,提示我們 等號兩邊的型別不相同,這是為什麼呢?眼尖的同學肯定發現了,說這兩個型別不同,肯定不能直接賦值,進行一下指標強轉就好了,雖然我們都知道這樣的做法,但很少有人說出為什麼第乙個就可以了?其實這裡面涉及到「相容」的問題。

標準規定,要使兩種型別賦值合法,必須滿足下面的條件:

兩個運算元都是指向有限定符或無限定符的相容型別的指標,左邊指標所指向的型別必須具有右邊指標所指向型別的全部限定符。
所以對於注釋1,左運算元是乙個指向有const限定符的char的指標。

右運算元是乙個指向沒有限定符的char指標

char型別與char型別是相容的,左運算元所指向的型別具有右運算元指向的限定符(無),再加上自身的限定符(const),所以這種賦值是成立的,但反過來則不可以。

2.4 static與非static

static關鍵字意為:靜態的,不變的。

2.41 以c為說明物件

在c裡面static主要有兩種作用:

1,它可以改變區域性變數的生命週期,我們知道乙個區域性變數只在它所在的作用域內有效,出了這個作用域,則變數就不再具有相應的意義,但是對於static修飾的區域性變數,它的生命週期則變為整個程式的生命週期,但它的作用域不發生改變。

區域性變數儲存於堆疊之中,而靜態變數儲存與全域性區(靜態區,且已被初始化)或bss段(未被初始化的全域性變數與static變數)。

2,修改變數或函式的可見性

在c/c++中,預設全域性變數或static函式在鏈結時是全域性可見的(這意味著你可以在別的地方經過聲名使用相應的變數或方法),可如果加上了static關鍵字,則該變數或函式只在本檔案內有效,相當於是私有的,外界不可見。接下來看個例子。

void test3()

#include"test1.h"

int x = 3;

int main()

列印結果:x=4

我們在test1.h中聲名並定義了乙個函式為test3,此時我想在該函式裡使用main.cpp裡面宣告的變數x(此時x為全域性變數),那麼只需要在函式中用extern關鍵字宣告x就好了,那麼在鏈結時編譯器會在其他檔案裡查詢關於x這個變數的定義,如果沒有找到便會丟擲變數未定義的問題。

此時我們若把x用static修飾又會怎樣呢?

我們來看執行結果:

此時我們發現x在test1.h中無法被解析了,這正是因為,在x宣告的地方使用了static修飾,所以在main.cpp裡面定義的全域性變數便在別的檔案中不可見了,這對於static修飾的函式來說亦是如此。

extern 關鍵字的作用

在上面的例子中我們正式引入了extern關鍵字,它的意思為:外來的。在c/c++中用來宣告乙個物件。

乙個物件可以被宣告為無數次,但它的定義卻只能有乙份。當遇到上述情況,我們想使用別處定義的變數或函式,只需要使用extern關鍵字對變數進行宣告,以後便可以直接來使用這個變數了。

extern 「c」關鍵字的作用

該關鍵字是c++中所使用的,我們知道c++是c的乙個超集,當我們在c++裡面想使用c的編譯,鏈結規則時便可以使用該關鍵字告訴編譯器。為什麼要這樣使用呢?

因為c++為了支援過載,它在聯編的時候(將函式體與函式名繫結到一起),是用函式名+函式的形參的方式來區分每個函式的(返回型別不支援這樣的特性。),而在c裡面並沒有過載這種特性,它在聯編的時候只以函式名來區分每個函式,所以如果使用c++的規則去鏈結c中定義的函式,則有可能發生找不到相應函式的問題,所以用c的編譯,鏈結方式就不會造成該問題了。

2.42 以c++為說明物件

在c++裡面最有特色的便為類吧,static關鍵字可以用來修飾類的成員以及成員函式,被static修飾的成員及成員函式是作為類的一部分而存在的,不同的類的物件共享這些靜態成員。因此靜態成員函式也不存在預設的this指標。

1,靜態的物件只能用來呼叫靜態的成員函式。

2,靜態成員需要在類外進行初始化

3,普通的物件可以呼叫靜態成員函式

2.5 explicit關鍵字

該關鍵字用於c++之中,意思為:明確的,清楚的,它用於修飾只帶有乙個引數的建構函式,主要為了防止形參隱式型別轉換所帶來的錯誤,通常該錯誤發生之後是很難發現的,因為編譯器並不報錯。該關鍵字的出現可以使物件的建立者每次都顯示的呼叫建構函式。

關鍵字 一些關鍵字用法總結

register 用register宣告的變數稱暫存器變數,在可能的情況下會直接存放在機器的暫存器中 但對32位編譯器不起作用,當global optimizations 全域性優化 開的時候,它會做出選擇是否放在自己的暫存器中 不過其它與register關鍵字有關的其它符號都對32位編譯器有效。c...

MySql一些關鍵字

使用distinct關鍵字,只返回不同的值 distinct關鍵字,它必須直接放在列名的前面 eg select distinct id from stu 注意 不能部分使用distinct distinct關鍵字應用於所有列而不僅是前置它的列。如果給出select distinct id,name...

一些關鍵字或模板

一 dynamic cast 使用dynamic cast乙個繼承層次內進行轉化的指標 引用。dynamic cast依賴於rtti資訊,在轉換時,dynamic cast會檢查轉換的source物件是否真的可以轉換成target型別,這種檢查不是語法上的,而是真實情況的檢查。被轉換的型別必須是多型...