- 相關(guān)推薦
C語言關(guān)鍵字
C語言關(guān)鍵字1
一、皇帝身邊的小太監(jiān)----寄存器
不知道什么是寄存器?那見過太監(jiān)沒有?沒有?其實我也沒有。沒見過不要緊,見過就麻煩大了。^_^,大家都看過古裝戲,那些皇帝們要閱讀奏章的時候,大臣總是先將奏章交給皇帝旁邊的小太監(jiān),小太監(jiān)呢再交給皇帝同志處理。這個小太監(jiān)只是個中轉(zhuǎn)站,并無別的功能。
好,那我們再聯(lián)想到我們的CPU。CPU 不就是我們的皇帝同志么?大臣就相當(dāng)于我們的`內(nèi)存,數(shù)據(jù)從他這拿出來。那小太監(jiān)就是我們的寄存器了(這里先不考慮CPU 的高速緩存區(qū))。數(shù)據(jù)從內(nèi)存里拿出來先放到寄存器,然后CPU 再從寄存器里讀取數(shù)據(jù)來處理,處理完后同樣把數(shù)據(jù)通過寄存器存放到內(nèi)存里,CPU 不直接和內(nèi)存打交道。這里要說明的一點是:小太監(jiān)是主動的從大臣手里接過奏章,然后主動的交給皇帝同志,但寄存器沒這么自覺,它從不主動干什么事。一個皇帝可能有好些小太監(jiān),那么一個CPU 也可以有很多寄存器,不同型號的CPU 擁有寄存器的數(shù)量不一樣。
為啥要這么麻煩啊?速度!就是因為速度。寄存器其實就是一塊一塊小的存儲空間,只不過其存取速度要比內(nèi)存快得多。進(jìn)水樓臺先得月嘛,它離CPU 很近,CPU 一伸手就拿到數(shù)據(jù)了,比在那么大的一塊內(nèi)存里去尋找某個地址上的數(shù)據(jù)是不是快多了?那有人問既然它速度那么快,那我們的內(nèi)存硬盤都改成寄存器得了唄。我要說的是:你真有錢!
二、舉例
register修飾符暗示編譯程序相應(yīng)的變量將被頻繁地使用,如果可能的'話,應(yīng)將其保存在CPU的寄存器中,以加快其存儲速度。例如下面的內(nèi)存塊拷貝代碼,
#ifdef NOSTRUCTASSIGN
memcpy (d, s, l)
{
register char *d;
register char *s;
register int i;
while (i--)
*d++ = *s++;
}
#endif
三、使用register 修飾符的注意點
但是使用register修飾符有幾點限制。
首先,register變量必須是能被CPU所接受的類型。這通常意味著register變量必須是一個單個的值,并且長度應(yīng)該小于或者等于整型的長度。不過,有些機器的寄存器也能存放浮點數(shù)。
其次,因為register變量可能不存放在內(nèi)存中,所以不能用“&”來獲取register變量的地址。
由于寄存器的數(shù)量有限,而且某些寄存器只能接受特定類型的數(shù)據(jù)(如指針和浮點數(shù)),因此真正起作用的register修飾符的數(shù)目和類型都依賴于運行程序的機器,而任何多余的register修飾符都將被編譯程序所忽略。
在某些情況下,把變量保存在寄存器中反而會降低程序的運行速度。因為被占用的寄存器不能再用于其它目的;或者變量被使用的.次數(shù)不夠多,不足以裝入和存儲變量所帶來的額外開銷。
早期的C編譯程序不會把變量保存在寄存器中,除非你命令它這樣做,這時register修飾符是C語言的一種很有價值的補充。然而,隨著編譯程序設(shè)計技術(shù)的進(jìn)步,在決定那些變量應(yīng)該被存到寄存器中時,現(xiàn)在的C編譯環(huán)境能比程序員做出更好的決定。實際上,許多編譯程序都會忽略register修飾符,因為盡管它完全合法,但它僅僅是暗示而不是命令。
C語言關(guān)鍵字2
為什么引入const?
const 推出的初始目的,正是為了取代預(yù)編譯指令,消除它的缺點,同時繼承它的優(yōu)點。
const關(guān)鍵字使用非常的靈活,這一點和php差別很大,php中const用來在類中定義一個常量,而在c中,const因位置不同有不同的作用,因情景不同有不同的角色,使用起來也是非常的靈活。
(1):const用來修飾普通的.變量(指針變量除外)的時候,const type name 和 type const name 這兩種形式是完全等價的,都表示其是常量,不能進(jìn)行修改。
#include
int main(){
const int num =23;
printf("result=%dn",num);
num =31;
printf("result=%dn",num); //報錯,num是常量,不能修改
}
(2):const用來修飾指針變量的時候,分為以下四種情況
1、const type *name :這種情況下,const修飾的指針變量name所指向的type類型對象,也就是說指向的這個對象是不能進(jìn)行修改的,因為其是常量,而指針變量確實可以進(jìn)行修改的
#include
int main(){
int tmp = 23;
const int *num = &tmp;
printf("result=%dn",*num);
(*num) = 24; //報錯,因為指針num指向的int類型的對象是不能進(jìn)行修改的
printf("result=%dn",*num);
}
2、type const *name :這種情況下,const修飾的指針變量name所指向的type類型對象,意思完全同上,只是顛倒了以下順序。
#include
int main(){
int tmp = 23;
int const* num = &tmp;
printf("result=%dn",*num);
(*num) = 24; //報錯,因為指針num指向的int類型的對象是不能進(jìn)行修改的
printf("result=%dn",*num);
}
3、type * const name :這種情況下,const修飾的指針變量name,也就是說這個指針變量的值是不能進(jìn)行修改的,但是指針變量所指向的對象確實可以修改的
#include
int main(){
int tmp = 100;
int *const num = &tmp;
printf("result=%dn",*num);
int change = 23;
num = &change; //報錯,因為指針num是不能進(jìn)行修改的
printf("result=%dn",*num);
}
4、const type * const name :這種情況下,const修飾的指針變量name以及指針變量name所指向的對象,也就是說這個指針變量以及這個指針變量所指向的對象都是不能進(jìn)行修改的
(3):const在函數(shù)中的參數(shù)的作用:
void get_value( const int num ){
num=23; //報錯
}
調(diào)用get_value()函數(shù)的時候,傳遞num參數(shù)到函數(shù),因為定義了const,所以在函數(shù)中num是不能進(jìn)行修改的
C語言關(guān)鍵字3
數(shù)據(jù)類型修飾相關(guān)
auto按照自動的方式進(jìn)行變量的存儲
const定義常量或常參數(shù)
extern聲明外部變量或函數(shù)
register指定變量的存儲類型是寄存器變量
static指定變量的存儲類型是靜態(tài)變量,或指定函數(shù)是靜態(tài)函數(shù)
volatile變量的`值可能在程序的外部被改變
數(shù)據(jù)類型相關(guān)
char字符型數(shù)據(jù)
short定義短整型變量或指針
int整型數(shù)據(jù)
long長整型數(shù)據(jù)
signed有符號的整型數(shù)據(jù)
unsigned定義無符號的整型變量或數(shù)據(jù)
float單精度浮點型數(shù)據(jù)
double雙精度浮點型數(shù)據(jù)
struct結(jié)構(gòu)體型數(shù)據(jù)
enum枚舉型類型
union聯(lián)合型數(shù)據(jù)
void空型數(shù)據(jù)
typedef為數(shù)據(jù)類型定義別名
流程控制相關(guān)
continue結(jié)束本次循環(huán)進(jìn)入下一次循環(huán)
break跳出循環(huán)或switch語句
switch定義switch語句
case定義switch中的case子句
default定義switch中的default子句
do定義do-while語句
while定義while或do-while語句
if定義if語句或if-else語句
else定義if-else語句
for定義for循環(huán)語句
goto定義goto語句
預(yù)處理相關(guān)
#include包含頭文件
#define定義宏
#undef取消已經(jīng)定義的宏
#if定義條件編譯的條件
#ifdef定義條件編譯的條件
ifndef定義條件編譯的條件
#elif定義條件編譯的條件
#endif結(jié)束條件編譯
C語言關(guān)鍵字4
通俗一點說: 枚舉就是你的那個變量就那么幾種狀態(tài),不會出現(xiàn)別的,而且你也不想被五一修改,那么就定義為枚舉好了。狀態(tài)機的狀態(tài),用這個表示最合適不過了。
下面說一說枚舉和define的應(yīng)用場景
兩enum是一個類型和變量了。
define 只是一個宏定義
define特點:
優(yōu)點:宏定義可為多種類型的值,如字符串、整型、浮點型等。
補充:其實他還可以用于各種函數(shù)替換,變量組合拼湊......這些是枚舉所無法達(dá)到的.。
缺點:沒有范圍限制(全局范圍有效),容易發(fā)生沖突,產(chǎn)生不確定的結(jié)果;
多個相關(guān)的值一起定義時比較散亂。
enum特點:
缺點:只能為整型值
優(yōu)點:遵循范圍規(guī)則,不易和其它定義發(fā)生沖突。
多個相關(guān)值一組,比較清晰。
一般情況下二者可選時盡量用enum。
再說一遍一般情況下二者可選時盡量用enum。
另外debug的時候,枚舉變量顯示的數(shù)據(jù),是你的枚舉,調(diào)試很方便的。
C語言關(guān)鍵字5
auto :聲明自動變量
short :聲明短整型變量或函數(shù)
int: 聲明整型變量或函數(shù)
long :聲明長整型變量或函數(shù)
float:聲明浮點型變量或函數(shù)
double :聲明雙精度變量或函數(shù)
char :聲明字符型變量或函數(shù)
struct:聲明結(jié)構(gòu)體變量或函數(shù)
union:聲明共用數(shù)據(jù)類型
enum :聲明枚舉類型
typedef:用以給數(shù)據(jù)類型取別名
const :聲明只讀變量
unsigned:聲明無符號類型變量或函數(shù)
signed:聲明有符號類型變量或函數(shù)
extern:聲明變量是在其他文件正聲明
register:聲明寄存器變量
static :聲明靜態(tài)變量
volatile:說明變量在程序執(zhí)行中可被隱含地改變
void :聲明函數(shù)無返回值或無參數(shù),聲明無類型指針
if:條件語句
else :條件語句否定分支(與 if 連用)
switch :用于開關(guān)語句 case:開關(guān)語句分支
for:一種循環(huán)語句
do :循環(huán)語句的循環(huán)體
while :循環(huán)語句的`循環(huán)條件
goto:無條件跳轉(zhuǎn)語句
continue:結(jié)束當(dāng)前循環(huán),開始下一輪循環(huán)
break:跳出當(dāng)前循環(huán)
default:開關(guān)語句中的“其他”分支
sizeof:計算數(shù)據(jù)類型長度
return :子程序返回語句(可以帶參數(shù),也可不帶參數(shù))循環(huán)條件
C語言關(guān)鍵字6
要理解 restrict,先要知道什么是 Pointer aliasing。
Pointer aliasing 是指兩個或以上的指針指向同一數(shù)據(jù),例如
int i = 0;
int *a = &i;
int *b = &i;
這樣會有什么問題呢?
如果編譯器采用最安全的假設(shè),即不理會兩個指針會否指向同一數(shù)據(jù),那么通過指針讀寫數(shù)據(jù)是很直觀的。
然而,這種假設(shè)會令編譯器無法優(yōu)化,例如:
int foo(int *a, int *b)
{
*a = 5;
*b = 6;
return *a + *b; // 不一定是 11!
}
如果 a 和 b 都指向同一數(shù)據(jù),*b = 6 會導(dǎo)致 *a = 6,返回12。所以編譯器在做 *a + *b 的時候,需要重新讀取 *a 指向的數(shù)據(jù):
foo:
movl $5, (%rdi) # 存儲 5 至 *a
movl $6, (%rsi) # 存儲 6 至 *b
movl (%rdi), %eax # 重新讀取 *a (因為有可能被上一行指令造成改變)
addl $6, %eax # 加上 6
ret
如果我們確保兩個指針不指向同一數(shù)據(jù),就可以用 restrict 修飾指針類型:
int rfoo(int *restrict a, int *restrict b)
{
*a = 5;
*b = 6;
return *a + *b;
}
編譯器就可以根據(jù)這個信息,做出優(yōu)化:
rfoo:
movl $11, %eax # 在編譯期已計算出 11
movl $5, (%rdi) # 存儲 5 至 *a
movl $6, (%rsi) # 存儲 6 至 *b
ret
但如果用了 restrict 去修飾兩個指針,而它們在作用域內(nèi)又指向同一地址,那么是未定義行為。
總括而言,restrict 是為了告訴編譯器額外信息(兩個指針不指向同一數(shù)據(jù)),從而生成更優(yōu)化的'機器碼。注意,編譯器是無法自行在編譯期檢測兩個指針是否 alias。如使用 restrict,程序員也要遵守契約才能得出正確的代碼(指針不能指向相同數(shù)據(jù))。
以個人經(jīng)驗而言,編寫代碼時通常會忽略 pointer aliasing 的問題。更常見是在性能剖測時,通過反編譯看到很多冗余的讀取指令,才會想到加入 restrict 關(guān)鍵字來提升性能。
C語言關(guān)鍵字7
A循環(huán)語句:
for:一種循環(huán)語句
do :循環(huán)語句的循環(huán)體
while :循環(huán)語句的.循環(huán)條件
break:跳出當(dāng)前循環(huán)
continue:結(jié)束當(dāng)前循環(huán),開始下一輪循環(huán) B條件語句:
if: 條件語句
else:條件語句否定分支(與 if 連用)
goto:無條件跳轉(zhuǎn)語句 C開關(guān)語句:
switch :用于開關(guān)語句
case:開關(guān)語句分支
default:開關(guān)語句中的“其他”分支 D返回語句:
return :子程序返回語句(可以帶參數(shù),也看不帶參數(shù))
C語言關(guān)鍵字8
(1) char :聲明字符型變量或函數(shù)
(2) double :聲明雙精度變量或函數(shù)
(3) enum :聲明枚舉類型
(4) float:聲明浮點型變量或函數(shù)
(5) int: 聲明整型變量或函數(shù)
(6) long :聲明長整型變量或函數(shù)
(7) short :聲明短整型變量或函數(shù)
(8) signed:聲明有符號類型變量或函數(shù)
(9) struct:聲明結(jié)構(gòu)體變量或函數(shù)
(10) union:聲明共用體(聯(lián)合)數(shù)據(jù)類型
(11) unsigned:聲明無符號類型變量或函數(shù)
(12) void :聲明函數(shù)無返回值或無參數(shù),聲明無類型指針
C語言關(guān)鍵字9
因為在app開發(fā)中,定義網(wǎng)絡(luò)鏈接或者設(shè)定常用變量時經(jīng)常會用到一些C中的`關(guān)鍵字,但很多同學(xué)只見其名而不知其意,今天就介紹2個開發(fā)中常用的C語言關(guān)鍵字,分別是C語言中的static和extern關(guān)鍵字。
1.static
static的.作用
修飾局部變量:
1.延長局部變量的生命周期,程序結(jié)束才會銷毀
2.局部變量只會生成一份內(nèi)存,只會初始化一次
3.改變局部變量的作用域
寫法:
//方法內(nèi)部static修飾的變量
//不管調(diào)用與否,只會調(diào)用一次
- (void)staticTest
{
// static修飾局部變量
static int age = 0;
age++;
NSLog(@"%d",age);
}
//即調(diào)用兩次該方法
//打印結(jié)果
//1
//2
修飾全局變量
1.只能在本文件中訪問,修改全局變量的作用域,生命周期不會改
2.避免重復(fù)定義全局變量
寫法:
// 全局變量:只有一份內(nèi)存,
//所有文件共享,與extern聯(lián)合使用。
// 寫在方法外部
// static修飾全局變量
static int age = 20;
//調(diào)用
extern int age;
NSLog(@"%d",age);
//打印結(jié)果
//20
2.extern
extern作用:
只是用來獲取全局變量(包括全局靜態(tài)變量)的值,不能用于定義變量
extern工作原理:
先在當(dāng)前文件查找有沒有全局變量,沒有找到,才會去其他文件查找。
C語言關(guān)鍵字10
標(biāo)識符
定義變量時,我們使用了諸如“a”“abc”“mn123”這樣的名字,它們都是程序員自己起的,一般能夠表達(dá)出變量的作用,這叫做標(biāo)識符(Identifier)。
標(biāo)識符就是程序員自己起的名字,除了變量名,后面還會講到函數(shù)名、宏名、結(jié)構(gòu)體名等。不過,名字也不能隨便起,C語言規(guī)定,標(biāo)識符只能由字母(A~Z, a~z)、數(shù)字(0~9)和下劃線(_)組成,并且第一個字符必須是字母或下劃線。
以下標(biāo)識符是合法的:
a, x, x3, BOOK_1, sum5
以下標(biāo)識符是非法的:
3s 不能以數(shù)字開頭
s*T 出現(xiàn)非法字符*
-3x 不能以減號(-)開頭
bowy-1 出現(xiàn)非法字符減號(-)
在使用標(biāo)識符時還必須注意以下幾點:
C語言雖然不限制標(biāo)識符的長度,但是它受到不同編譯器的限制,同時也受到具體機器的限制。例如在某個編譯器中規(guī)定標(biāo)識符前128位有效,當(dāng)兩個標(biāo)識符前128位相同時,則被認(rèn)為是同一個標(biāo)識符。
在標(biāo)識符中,大小寫是有區(qū)別的,例如BOOK和book 是兩個不同的標(biāo)識符。
標(biāo)識符雖然可由程序員隨意定義,但標(biāo)識符是用于標(biāo)識某個量的符號,因此,命名應(yīng)盡量有相應(yīng)的意義,以便于閱讀理解,作到“顧名思義”。
關(guān)鍵字
關(guān)鍵字(Keywords)是由C語言規(guī)定的具有特定意義的字符串,通常也稱為保留字,例如 int、char、long、float、unsigned 等。我們定義的標(biāo)識符不能與關(guān)鍵字相同,否則會出現(xiàn)錯誤。
你也可以將關(guān)鍵字理解為具有特殊含義的標(biāo)識符,它們已經(jīng)被系統(tǒng)使用,我們不能再使用了。
標(biāo)準(zhǔn)C語言中一共規(guī)定了32個關(guān)鍵字,大家可以參考C語言關(guān)鍵字及其解釋[共32個],后續(xù)我們會一一講解。
注釋
注釋(Comments)可以出現(xiàn)在代碼中的.任何位置,用來向用戶提示或解釋程度的意義。程序編譯時,會忽略注釋,不做任何處理,就好像它不存在一樣。
C語言支持單行注釋和多行注釋:
單行注釋以//開頭,直到本行末尾(不能換行);
多行注釋以/*開頭,以*/結(jié)尾,注釋內(nèi)容可以有一行或多行。
一個使用注釋的例子:
/* Powered by: c.biancheng.net Author: xiao p Date: 20xx-6-26*/#includeint main(){ /* puts 會在末尾自動添加換行符 */ puts("http://c.biancheng.net"); printf("C語言中文網(wǎng)"); //printf要手動添加換行符 return 0;}
運行結(jié)果:
http://c.biancheng.net
C語言中文網(wǎng)
在調(diào)試程序的過程中可以將暫時不使用的語句注釋掉,使編譯器跳過不作處理,待調(diào)試結(jié)束后再去掉注釋。
需要注意的是,多行注釋不能嵌套使用。例如下面的注釋是錯誤的:
/*C語言/*中文*/網(wǎng)*/
而下面的注釋是正確的:
/*C語言中文網(wǎng)*/ /*c.biancheng.net*/
C語言關(guān)鍵字11
const 我們稱之為常量修飾符,意即其所修飾的對象為常量(immutable)。
我們來分情況看語法上它該如何被使用。
1、函數(shù)體內(nèi)修飾局部變量。
例:
void func(){
const int a=0;
}
首先,我們先把const這個單詞忽略不看,那么a是一個int類型的局部自動變量,
我們給它賦予初始值0。
然后再看const.
const作為一個類型限定詞,和int有相同的地位。
const int a;
int const a;
是等價的。于是此處我們一定要清晰的明白,const修飾的對象是誰,是a,和int沒
有關(guān)系。const 要求他所修飾的對象為常量,不可被改變,不可被賦值,不可作為左值(l-value)。
這樣的寫法也是錯誤的。
const int a;
a=0;
這是一個很常見的使用方式:
const double pi=3.14;
在程序的后面如果企圖對pi再次賦值或者修改就會出錯。
然后看一個稍微復(fù)雜的例子。
const int* p;
還是先去掉const 修飾符號。
注意,下面兩個是等價的。
int* p;
int *p;
其實我們想要說的是,*p是int類型。那么顯然,p就是指向int的指針。
同理
const int* p;
其實等價于
const int (*p);
int const (*p);
即,*p是常量。也就是說,p指向的數(shù)據(jù)是常量。
于是
p+=8; //合法
*p=3; //非法,p指向的數(shù)據(jù)是常量。
那么如何聲明一個自身是常量指針呢?方法是讓const盡可能的`靠近p;
int* const p;
const右面只有p,顯然,它修飾的是p,說明p不可被更改。然后把const去掉,可以
看出p是一個指向 int形式變量的指針。
于是
p+=8; //非法
*p=3; //合法
再看一個更復(fù)雜的例子,它是上面二者的綜合
const int* const p;
說明p自己是常量,且p指向的變量也是常量。
于是
p+=8; //非法
*p=3; //非法
const 還有一個作用就是用于修飾常量靜態(tài)字符串。
例如:
const char* name=David;
如果沒有const,我們可能會在后面有意無意的寫name[4]='x'這樣的語句,這樣會
導(dǎo)致對只讀內(nèi)存區(qū)域的賦值,然后程序會立刻異常終止。有了 const,這個錯誤就
能在程序被編譯的時候就立即檢查出來,這就是const的好處。讓邏輯錯誤在編譯
期被發(fā)現(xiàn)。
const 還可以用來修飾數(shù)組
const char s[]=David;
與上面有類似的作用。
2、在函數(shù)聲明時修飾參數(shù)
來看實際中的一個例子。
void * memmove(void *dst, const void *src, size_t len);
這是標(biāo)準(zhǔn)庫中的一個函數(shù),用于按字節(jié)方式復(fù)制字符串(內(nèi)存)。
它的第一個參數(shù),是將字符串復(fù)制到哪里去(dest),是目的地,這段內(nèi)存區(qū)域必須
是可寫。
它的第二個參數(shù),是要將什么樣的字符串復(fù)制出去,我們對這段內(nèi)存區(qū)域只做讀
取,不寫。
于是,我們站在這個函數(shù)自己的角度來看,src 這個指針,它所指向的內(nèi)存內(nèi)所存
儲的數(shù)據(jù)在整個函數(shù)執(zhí)行的過程中是不變。于是src所指向的內(nèi)容是常量。于是就
需要用const修飾。
例如,我們這里這樣使用它。
const char* s=hello;
char buf[100];
memmove(buf,s,6); //這里其實應(yīng)該用strcpy或memcpy更好
如果我們反過來寫,
memmove(s,buf,6);
那么編譯器一定會報錯。事實是我們經(jīng)常會把各種函數(shù)的參數(shù)順序?qū)懛础J聦嵤蔷?/p>
譯器在此時幫了我們大忙。如果編譯器靜悄悄的不報錯,(在函數(shù)聲明處去掉
const即可),那么這個程序在運行的時候一定會崩潰。
這里還要說明的一點是在函數(shù)參數(shù)聲明中const一般用來聲明指針而不是變量本身。
例如,上面的size_t len,在函數(shù)實現(xiàn)的時候可以完全不用更改len的值,那么是否
應(yīng)該把len也聲明為常量呢?可以,可以這么做。我們來分析這么做有什么優(yōu)劣。
如果加了const,那么對于這個函數(shù)的實現(xiàn)者,可以防止他在實現(xiàn)這個函數(shù)的時候修
改不需要修改的值(len),這樣很好。
但是對于這個函數(shù)的使用者,
1。這個修飾符號毫無意義,我們可以傳遞一個常量整數(shù)或者一個非常量整數(shù)過
去,反正對方獲得的只是我們傳遞的一個copy。
2。暴露了實現(xiàn)。我不需要知道你在實現(xiàn)這個函數(shù)的時候是否修改過len的值。
所以,const一般只用來修飾指針。
再看一個復(fù)雜的例子
int execv(const char *path, char *const argv[]);
著重看后面這個,argv.它代表什么。
如果去掉const,我們可以看出
char * argv[];
argv是一個數(shù)組,它的每個元素都是char *類型的指針。
如果加上const.那么const修飾的是誰呢?他修飾的是一個數(shù)組,argv[],意思就是
說這個數(shù)組的元素是只讀的。那么數(shù)組的元素的是什么類型呢?是char *類型的指
針.也就是說指針是常量,而它指向的數(shù)據(jù)不是。
于是
argv[1]=NULL; //非法
argv[0][0]='a'; //合法
3、全局變量。
我們的原則依然是,盡可能少的使用全局變量。
我們的第二條規(guī)則 則是,盡可能多的使用const。
如果一個全局變量只在本文件中使用,那么用法和前面所說的函數(shù)局部變量沒有什
么區(qū)別。
如果它要在多個文件間共享,那么就牽扯到一個存儲類型的問題。
有兩種方式。
1.使用extern
例如
/* file1.h */
extern const double pi;
/* file1.c */
const double pi=3.14;
然后其他需要使用pi這個變量的,包含file1.h
#include file1.h
或者,自己把那句聲明復(fù)制一遍就好。
這樣做的結(jié)果是,整個程序鏈接完后,所有需要使用pi這個變量的共享一個存儲區(qū)域。
最后,說說const的作用。
const 的好處,是引入了常量的概念,讓我們不要去修改不該修改的內(nèi)存。直接的
作用就是讓更多的邏輯錯誤在編譯期被發(fā)現(xiàn)。所以我們要盡可能的多使用const。
但是很多人并不習(xí)慣使用它,更有甚者,是在整個程序 編寫/調(diào)試 完后才補
const。如果是給函數(shù)的聲明補const,尚好。如果是給 全局/局部變量補const,那
么……那么,為時已晚,無非是讓代碼看起來更漂亮了。
C語言關(guān)鍵字12
其實在寫代碼的時候,關(guān)鍵字還是用的比較多的,這里主要就平常中用到的常用關(guān)鍵字進(jìn)行總結(jié),便于更全面的理解其在代碼中的意圖。下文主要介紹C語言的關(guān)鍵字define的相關(guān)內(nèi)容。
1 、防止一個頭文件被重復(fù)包含
當(dāng)我們的程序很大很大時,比如超過20000行時,我們很可能沒有辦法對所有的文件都有清楚的了解,特別是.h
文件,那么我們怎么做才能避免include時重復(fù)包含呢 答案就是#define
如下:
a.h b.h c.h 三個文件
a.h 內(nèi)容
int variable_a;
b.h 內(nèi)容
#include "a.h"
int variable_b;
c.h內(nèi)容
#include "a.h"
#include "b.h"
int c;
那么c.h就包含了兩次a.h,那如何避免呢
#ifndef A_H
#define A_H
//頭文件A
#endif
這樣就可以保證a.h只會被包含一次
2、簡單替換
#define MACRO_A 15
后面出現(xiàn)的MACRO_A 都會被替換為15這個數(shù)
3、帶參數(shù)的替換
#define ABS( a ) ( ((a)>0) ? (a) : (-(a)) )
可以使用宏替換來實現(xiàn)簡單的`函數(shù)。
以下是#define的高級用法
4、高級用法
define中的三個特殊符號:#,##,#@
#defineConn(x,y) x##y
#defineToChar(x) #@x
#defineToString(x) #x
(1)x##y表示什么?表示x連接y,舉例說:
intn=Conn(123,456);/* 結(jié)果就是n=123456;*/
char*str=Conn("asdf","adf");/*結(jié)果就是 str = "asdfadf";*/
(2)再來看#@x,其實就是給x加上單引號,結(jié)果返回是一個const char。舉例說:
char a = ToChar(1);結(jié)果就是a='1';
做個越界試驗char a = ToChar(123);結(jié)果就錯了;
但是如果你的參數(shù)超過四個字符,編譯器就給給你報錯了!
error C20xx: too many characters in constant :P
(3)最后看看#x,估計你也明白了,他是給x加雙引號
char* str = ToString(123132);就成了str="123132";
C語言關(guān)鍵字13
1.作用于變量:
用static聲明局部變量-------局部變量指在代碼塊{}內(nèi)部定義的變量,只在代碼塊內(nèi)部有效(作用域),其缺省的存儲方式是自動變量或說是動態(tài) 存儲的,即指令執(zhí)行到變量定義處時才給變量分配存儲單元,跳出代碼塊時釋放內(nèi)存單元(生命期)。用static聲明局部變量時,則改變變量的存儲方式(生 命期),使變量成為靜態(tài)的局部變量,即編譯時就為變量分配內(nèi)存,直到程序退出才釋放存儲單元。這樣,使得該局部變量有記憶功能,可以記憶上次的數(shù)據(jù),不過 由于仍是局部變量,因而只能在代碼塊內(nèi)部使用(作用域不變)。
用static聲明外部變量-------外部變量指在所有代碼塊{}之外定義的變量,它缺省為靜態(tài)變量,編譯時分配內(nèi)存,程序結(jié)束時釋放內(nèi) 存單元。同時其作用域很廣,整個文件都有效甚至別的文件也能引用它。為了限制某些外部變量的作用域,使其只在本文件中有效,而不能被其他文件引用,可以用 static關(guān)鍵字對其作出聲明。
總結(jié):用static聲明局部變量,使其變?yōu)殪o態(tài)存儲方式(靜態(tài)數(shù)據(jù)區(qū)),作用域不變;用static聲明外部變量,其本身就是靜態(tài)變量,這只會改變其連接方式,使其只在本文件內(nèi)部有效,而其他文件不可連接或引用該變量。
2.作用于函數(shù):
使用static用于函數(shù)定義時,對函數(shù)的連接方式產(chǎn)生影響,使得函數(shù)只在本文件內(nèi)部有效,對其他文件是不可見的。這樣的函數(shù)又叫作靜態(tài)函數(shù)。使用靜態(tài)函數(shù)的好處是,不用擔(dān)心與其他文件的同名函數(shù)產(chǎn)生干擾,另外也是對函數(shù)本身的一種保護機制。
如果想要其他文件可以引用本地函數(shù),則要在函數(shù)定義時使用關(guān)鍵字extern,表示該函數(shù)是外部函數(shù),可供其他文件調(diào)用。另外在要引用別的文件中定義的外部函數(shù)的文件中,使用extern聲明要用的外部函數(shù)即可。
const作用: “只讀(readonly)”
1.定義常量
(1)const
修飾變量,以下兩種定義形式在本質(zhì)上是一樣的。它的含義是:const修飾的類型為TYPE的變量value是不可變的,readonly。
TYPE const ValueName = value;
const TYPE ValueName = value;
(2)將const改為外部連接,作用于擴大至全局,編譯時會分配內(nèi)存,并且可以不進(jìn)行初始化,僅僅作為聲明,編譯器認(rèn)為在程序其他地方進(jìn)行了定義.
extend const int ValueName = value;
2.指針使用CONST
(1)指針本身是常量不可變
char * const pContent;
const (char*) pContent;
(2)指針?biāo)赶虻膬?nèi)容是常量不可變
const char *pContent;
char const *pContent;
(3)兩者都不可變
const char* const pContent;
(4)還有其中區(qū)別方法,沿著*號劃一條線:如果const位于*的左側(cè),則const就是用來修飾指針?biāo)赶虻淖兞浚粗羔樦赶驗槌A?如果const位于*的右側(cè),const就是修飾指針本身,即指針本身是常量。
3.函數(shù)中使用CONST
(1)const修飾函數(shù)參數(shù)
a.傳遞過來的參數(shù)在函數(shù)內(nèi)不可以改變(無意義,因為Var本身就是形參)
void function(const int Var);
b.參數(shù)指針?biāo)竷?nèi)容為常量不可變
void function(const char* Var);
c.參數(shù)指針本身為常量不可變(也無意義,因為char* Var也是形參)
void function(char* const Var);
d.參數(shù)為引用,為了增加效率同時防止修改。修飾引用參數(shù)時:
void function(const Class& Var); //引用參數(shù)在函數(shù)內(nèi)不可以改變
void function(const TYPE& Var); //引用參數(shù)在函數(shù)內(nèi)為常量不可變
這樣的一個const引用傳遞和最普通的函數(shù)按值傳遞的效果是一模一樣的.,他禁止對引用的對象的一切修改,唯一不同的是按值傳遞會先建立一個類對象的副本, 然后傳遞過去,而它直接傳遞地址,所以這種傳遞比按值傳遞更有效.另外只有引 用的const傳遞可以傳遞一個臨時對象,因為臨時對象都是const屬性, 且是不可見的,他短時間存在一個局部域中,所以不能使用指針,只有引用的 const傳遞能夠捕捉到這個家伙.
(2)const 修飾函數(shù)返回值
const修飾函數(shù)返回值其實用的并不是很多,它的含義和const修飾普通變量以及指針的含義基本相同。
a.
const int fun1() //這個其實無意義,因為參數(shù)返回本身就是賦值。
b.
const int * fun2() //調(diào)用時
const int *pValue = fun2(); //我們可以把fun2()看作成一個變量,即指針內(nèi)容不可變。
c.
int* const fun3() //調(diào)用時
int * const pValue = fun2(); //我們可以把fun2()看作成一個變量,即指針本身不可變。
C語言關(guān)鍵字14
1、static 修飾函數(shù)
函數(shù)的訪問范圍就被限定在本文件以內(nèi),任何本文件以外內(nèi)容的訪問此函數(shù),都是非法和無效的,編譯不會通過,提示找不到該符號。 所以,我們在進(jìn)行一個函數(shù)設(shè)計的時候,首先需要考慮的就是,這個函數(shù)的作用是什么,作用范圍是什么,我們應(yīng)該怎么去保證模塊化。如果沒有被外部文件訪問,那么就把它限定為static。這就是這個static 修飾函數(shù)的用處。
2、static 修飾變量
無論在文件的哪個位置,用static修飾 變量,這個變量運行時都是占用的'RAM里的靜態(tài)全局?jǐn)?shù)據(jù)區(qū),再說一遍,靜態(tài)全局。在程序運行的整個生命周期內(nèi)是不會釋放的,這個我們也在前面單片機相關(guān)的文章里講過了。
既然static 修飾的變量和全局變量占用一樣的空間,為何還有static修飾,直接全局變量也就OK了啊? 對于硬件來說,有沒有static自然是一樣的,但是對于軟件卻不一樣。
函數(shù)外static修飾的變量,僅僅限定與本文件使用,所以你可以不關(guān)注本文件以外的信息,就知道這個變量是如何變化和使用的,這就減小了你閱讀程序的難度。
函數(shù)內(nèi)static修飾的變量,僅僅限定于本函數(shù)使用,所以你可以不關(guān)注本函數(shù)以外的信息,就知道這個變量是如何變化的,進(jìn)一步減小了你閱讀程序的難度,也方便查詢問題。
所以能定義為static的就盡量定義為static(后面會再更新如何去除static,書寫可重入函數(shù))。
C語言關(guān)鍵字15
1.static關(guān)鍵字
這個關(guān)鍵字的作用是餓很難強大的。
要對static關(guān)鍵字深入了解,首先需要掌握標(biāo)準(zhǔn)C程序的組成。
標(biāo)準(zhǔn)C程序一直由下列部分組成:
1)正文段——CPU執(zhí)行的機器指令部分,也就是你的程序。一個程序只有一個副本;只讀,這是為了防止程序由于意外事故而修改自身指令;
2)初始化數(shù)據(jù)段(數(shù)據(jù)段)——在程序中所有賦了初值的全局變量,存放在這里。
3)非初始化數(shù)據(jù)段(bss段)——在程序中沒有初始化的全局變量;內(nèi)核將此段初始化為0。
注意:只有全局變量被分配到數(shù)據(jù)段中。
4)棧——增長方向:自頂向下增長;自動變量以及每次函數(shù)調(diào)用時所需要保存的信息(返回地址;環(huán)境信息)。這句很關(guān)鍵,常常有筆試題會問到什么東西放到棧里面就足以說明。
5)堆——動態(tài)存儲分配。
在嵌入式C語言當(dāng)中,它有三個作用:
作用一:在函數(shù)體,一個被聲明為靜態(tài)的變量在這一函數(shù)被調(diào)用過程中維持其值不變。
這樣定義的變量稱為局部靜態(tài)變量:在局部變量之前加上關(guān)鍵字static,局部變量就被定義成為一個局部靜態(tài)變量。也就是上面的作用一中提到的在函數(shù)體內(nèi)定義的變量。除了類型符外,若不加其它關(guān)鍵字修飾,默認(rèn)都是局部變量。比如以下代碼:
void test1(void)
{
unsigned char a;
static unsigned char b;
…
a++;
b++;
}
在這個例子中,變量a是局部變量,變量b為局部靜態(tài)變量。作用一說明了局部靜態(tài)變量b的特性:在函數(shù)體,一個被聲明為靜態(tài)的變量(也就是局部靜態(tài)變量)在這一函數(shù)被調(diào)用過程中維持其值不變。這句話什么意思呢?若是連續(xù)兩次調(diào)用上面的函數(shù)test1:
void main(void)
{
…
test1();
test1();
…
}
然后使程序暫停下來,讀取a和b的值,你會發(fā)現(xiàn),a=1,b=2。怎么回事呢,每次調(diào)用test1函數(shù),局部變量a都會重新初始化為0x00;然后執(zhí)行a++;而局部靜態(tài)變量在調(diào)用過程中卻能維持其值不變。
通常利用這個特性可以統(tǒng)計一個函數(shù)被調(diào)用的次數(shù)。
聲明函數(shù)的一個局部變量,并設(shè)為static類型,作為一個計數(shù)器,這樣函數(shù)每次被調(diào)用的時候就可以進(jìn)行計數(shù)。這是統(tǒng)計函數(shù)被調(diào)用次數(shù)的最好的辦法,因為這個變量是和函數(shù)息息相關(guān)的.,而函數(shù)可能在多個不同的地方被調(diào)用,所以從調(diào)用者的角度來統(tǒng)計比較困難。代碼如下:
void count();
int main()
{
int i;
for (i = 1; i <= 3; i++)
{
count();
{
return 0;
}
void count()
{
static num = 0;
num++;
printf(" I have been called %d",num,"times/n");
}
輸出結(jié)果為:
I have been called 1 times.
I have been called 2 times.
I have been called 3 times.
看一下局部靜態(tài)變量的詳細(xì)特性,注意它的作用域。
1)內(nèi)存中的位置:靜態(tài)存儲區(qū)
2)初始化:未經(jīng)初始化的全局靜態(tài)變量會被程序自動初始化為0(自動對象的值是任意的,除非他被顯示初始化)
3)作用域:作用域仍為局部作用域,當(dāng)定義它的函數(shù)或者語句塊結(jié)束的時候,作用域隨之結(jié)束。
注:當(dāng)static用來修飾局部變量的時候,它就改變了局部變量的存儲位置,從原來的棧中存放改為靜態(tài)存儲區(qū)。但是局部靜態(tài)變量在離開作用域之后,并沒有被銷毀,而是仍然駐留在內(nèi)存當(dāng)中,直到程序結(jié)束,只不過我們不能再對他進(jìn)行訪問。
作用二:在模塊內(nèi)(但在函數(shù)體外),一個被聲明為靜態(tài)的變量可以被模塊內(nèi)所用函數(shù)訪問,但不能被模塊外其它函數(shù)訪問。它是一個本地的全局變量。
這樣定義的變量也稱為全局靜態(tài)變量:在全局變量之前加上關(guān)鍵字static,全局變量就被定義成為一個全局靜態(tài)變量。也就是上述作用二中提到的在模塊內(nèi)(但在函數(shù)體外)聲明的靜態(tài)變量。
定義全局靜態(tài)變量的好處:
<1>不會被其他文件所訪問,修改,是一個本地的局部變量。
全局變量的詳細(xì)特性,注意作用域,可以和局部靜態(tài)變量相比較:
1)內(nèi)存中的位置:靜態(tài)存儲區(qū)(靜態(tài)存儲區(qū)在整個程序運行期間都存在)
2)初始化:未經(jīng)初始化的全局靜態(tài)變量會被程序自動初始化為0(自動對象的值是任意的,除非他被顯示初始化)
3)作用域:全局靜態(tài)變量在聲明他的文件之外是不可見的。準(zhǔn)確地講從定義之處開始到文件結(jié)尾。
當(dāng)static用來修飾全局變量的時候,它就改變了全局變量的作用域(在聲明他的文件之外是不可見的),但是沒有改變它的存放位置,還是在靜態(tài)存儲區(qū)中。
作用三:在模塊內(nèi),一個被聲明為靜態(tài)的函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用。那就是,這個函數(shù)被限制在聲明它的模塊的本地范圍內(nèi)使用。
這樣定義的函數(shù)也成為靜態(tài)函數(shù):在函數(shù)的返回類型前加上關(guān)鍵字static,函數(shù)就被定義成為靜態(tài)函數(shù)。函數(shù)的定義和聲明默認(rèn)情況下是extern的,但靜態(tài)函數(shù)只是在聲明他的文件當(dāng)中可見,不能被其他文件所用。
定義靜態(tài)函數(shù)的好處:
<1>其他文件中可以定義相同名字的函數(shù),不會發(fā)生沖突
這里我一直強調(diào)數(shù)據(jù)和函數(shù)的本地化,這對于程序的結(jié)構(gòu)甚至優(yōu)化都有巨大的好處,更大的作用是,本地化的數(shù)據(jù)和函數(shù)能給人傳遞很多有用的信息,能約束數(shù)據(jù)和函數(shù)的作用范圍。在C++的對象和類中非常注重的私有和公共數(shù)據(jù)/函數(shù)其實就是本地和全局?jǐn)?shù)據(jù)/函數(shù)的擴展,這也從側(cè)面反應(yīng)了本地化數(shù)據(jù)/函數(shù)的優(yōu)勢。
最后說一下存儲說明符,在標(biāo)準(zhǔn)C語言中,存儲說明符有以下幾類:
auto、register、extern和static
對應(yīng)兩種存儲期:自動存儲期和靜態(tài)存儲期。
auto和register對應(yīng)自動存儲期。具有自動存儲期的變量在進(jìn)入聲明該變量的程序塊時被建立,它在該程序塊活動時存在,退出該程序塊時撤銷。
關(guān)鍵字extern和static用來說明具有靜態(tài)存儲期的變量和函數(shù)。用static聲明的局部變量具有靜態(tài)存儲持續(xù)期(static storage duration),或靜態(tài)范圍(static extent)。雖然他的值在函數(shù)調(diào)用之間保持有效,但是其名字的可視性仍限制在其局部域內(nèi)。靜態(tài)局部對象在程序執(zhí)行到該對象的聲明處時被首次初始化。
2. const 關(guān)鍵字
const關(guān)鍵字也是一個優(yōu)秀程序中經(jīng)常用到的關(guān)鍵字。關(guān)鍵字const 的作用是為給讀你代碼的人傳達(dá)非常有用的信息,實際上,聲明一個參數(shù)為常量是為了告訴了用戶這個參數(shù)的應(yīng)用目的。通過給優(yōu)化器一些附加的信息,使用關(guān)鍵字const 也許能產(chǎn)生更緊湊的代碼。合理地使用關(guān)鍵字const 可以使編譯器很自然地保護那些不希望被改變的參數(shù),防止其被無意的代碼修改。簡而言之,這樣可以減少bug的出現(xiàn)。
深入理解const關(guān)鍵字,你必須知道:
a. const關(guān)鍵字修飾的變量可以認(rèn)為有只讀屬性,但它絕不與常量劃等號。
如下代碼:
const int i=5;
int j=0;
...
i=j; //非法,導(dǎo)致編譯錯誤,因為只能被讀
j=i; //合法
b. const關(guān)鍵字修飾的變量在聲明時必須進(jìn)行初始化。如下代碼:
const int i=5; //合法
const int j; //非法,導(dǎo)致編譯錯誤
c. 用const聲明的變量雖然增加了分配空間,但是可以保證類型安全。const最初是從C++變化得來的,它可以替代define來定義常量。在舊版本(標(biāo)準(zhǔn)前)的c中,如果想建立一個常量,必須使用預(yù)處理器:
#define PI 3.14159
此后無論在何處使用PI,都會被預(yù)處理器以3.14159替代。編譯器不對PI進(jìn)行類型檢查,也就是說可以不受限制的建立宏并用它來替代值,如果使用不慎,很可能由預(yù)處理引入錯誤,這些錯誤往往很難發(fā)現(xiàn)。而且,我們也不能得到PI的地址(即不能向PI傳遞指針和引用)。const的出現(xiàn),比較好的.解決了上述問題。
d. C標(biāo)準(zhǔn)中,const定義的常量是全局的。
e. 必須明白下面語句的含義,我自己是反復(fù)記憶了許久才記住,方法是:若是想定義一個只讀屬性的指針,那么關(guān)鍵字const要放到‘* ’后面。
char *const cp; //指針不可改變,但指向的內(nèi)容可以改變
char const *pc1; //指針可以改變,但指向的內(nèi)容不能改變
const char *pc2; //同上(后兩個聲明是等同的)
f. 將函數(shù)傳入?yún)?shù)聲明為const,以指明使用這種參數(shù)僅僅是為了效率的原因,而不是想讓調(diào)用函數(shù)能夠修改對象的值。
參數(shù)const通常用于參數(shù)為指針或引用的情況,且只能修飾輸入?yún)?shù);若輸入?yún)?shù)采用“值傳遞”方式,由于函數(shù)將自動產(chǎn)生臨時變量用于復(fù)制該參數(shù),該參數(shù)本就不需要保護,所以不用const修飾。例子:
void fun0(const int * a );
void fun1(const int & a);
調(diào)用函數(shù)的時候,用相應(yīng)的變量初始化const常量,則在函數(shù)體中,按照const所修飾的部分進(jìn)行常量化,如形參為const int * a,則不能對傳遞進(jìn)來的指針?biāo)赶虻膬?nèi)容進(jìn)行改變,保護了原指針?biāo)赶虻膬?nèi)容;如形參為const int & a,則不能對傳遞進(jìn)來的引用對象進(jìn)行改變,保護了原對象的屬性。
g. 修飾函數(shù)返回值,可以阻止用戶修改返回值。(在嵌入式C中一般不用,主要用于C++)
h. const消除了預(yù)處理器的值替代的不良影響,并且提供了良好的類型檢查形式和安全性,在可能的地方盡可能的使用const對我們的編程有很大的幫助,前提是:你對const有了足夠的理解。
最后,舉兩個常用的標(biāo)準(zhǔn)C庫函數(shù)聲明,它們都是使用const的典范。
1.字符串拷貝函數(shù):char *strcpy(char *strDest,const char *strSrc);
2.返回字符串長度函數(shù):int strlen(const char *str);
3. volatile關(guān)鍵字
一個定義為volatile 的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設(shè)這個變量的值了。精確地說就是,優(yōu)化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器里的備份。
由于訪問寄存器的速度要快過RAM,所以編譯器一般都會作減少存取外部RAM的優(yōu)化。比如:
static int i=0;
int main(void)
{
...
while (1)
{
if (i)
dosomething();
}
}
/* Interrupt service routine. */
void ISR_2(void)
{
i=1;
}
程序的本意是希望ISR_2中斷產(chǎn)生時,在main當(dāng)中調(diào)用dosomething函數(shù),但是,由于編譯器判斷在main函數(shù)里面沒有修改過i,因此可能只執(zhí)行一次對從i到某寄存器的讀操作,然后每次if判斷都只使用這個寄存器里面的“i副本”,導(dǎo)致dosomething永遠(yuǎn)也不會被調(diào)用。
如果將將變量加上volatile修飾,則編譯器保證對此變量的讀寫操作都不會被優(yōu)化(肯定執(zhí)行)。此例中i也應(yīng)該如此說明。
一般說來,volatile用在如下的幾個地方:
1、中斷服務(wù)程序中修改的供其它程序檢測的變量需要加volatile;
2、多任務(wù)環(huán)境下各任務(wù)間共享的標(biāo)志應(yīng)該加volatile;
3、存儲器映射的硬件寄存器通常也要加volatile說明,因為每次對它的讀寫都可能有不同意義;
不懂得volatile 的'內(nèi)容將會帶來災(zāi)難,這也是區(qū)分C語言和嵌入式C語言程序員的一個關(guān)鍵因素。為強調(diào)volatile的重要性,再次舉例分析:
代碼一:
int a,b,c;
//讀取I/O空間0x100端口的內(nèi)容
a= inword(0x100);
b=a;
a=inword(0x100)
c=a;
代碼二:
volatile int a;
int a,b,c;
//讀取I/O空間0x100端口的內(nèi)容
a= inword(0x100);
b=a;
a=inword(0x100)
c=a;
在上述例子中,代碼一會被絕大多數(shù)編譯器優(yōu)化為如下代碼:
a=inword(0x100)
b=a;
c=a;
這顯然與編寫者的目的不相符,會出現(xiàn)I/O空間0x100端口漏讀現(xiàn)象,若是增加volatile,像代碼二所示的那樣,優(yōu)化器將不會優(yōu)化掉任何代碼.
從上面來看,volatile關(guān)鍵字是會降低編譯器優(yōu)化力度的,但它保證了程序的正確性,所以在適合的地方使用關(guān)鍵字volatile是件考驗編程功底的事情.
4.struct與typedef關(guān)鍵字
面對一個人的大型C/C++程序時,只看其對struct的使用情況我們就可以對其編寫者的編程經(jīng)驗進(jìn)行評估。因為一個大型的C/C++程序,勢必要涉及一些(甚至大量)進(jìn)行數(shù)據(jù)組合的結(jié)構(gòu)體,這些結(jié)構(gòu)體可以將原本意義屬于一個整體的數(shù)據(jù)組合在一起。從某種程度上來說,會不會用struct,怎樣用struct是區(qū)別一個開發(fā)人員是否具備豐富開發(fā)經(jīng)歷的標(biāo)志。
在網(wǎng)絡(luò)協(xié)議、通信控制、嵌入式系統(tǒng)的`C/C++編程中,我們經(jīng)常要傳送的不是簡單的字節(jié)流(char型數(shù)組),而是多種數(shù)據(jù)組合起來的一個整體,其表現(xiàn)形式是一個結(jié)構(gòu)體。
經(jīng)驗不足的開發(fā)人員往往將所有需要傳送的內(nèi)容依順序保存在char型數(shù)組中,通過指針偏移的方法傳送網(wǎng)絡(luò)報文等信息。這樣做編程復(fù)雜,易出錯,而且一旦控制方式及通信協(xié)議有所變化,程序就要進(jìn)行非常細(xì)致的修改。
用法:
在C中定義一個結(jié)構(gòu)體類型要用typedef:
typedef struct Student
{
int a;
}Stu;
于是在聲明變量的時候就可:Stu stu1;
如果沒有typedef就必須用struct Student stu1;來聲明
這里的Stu實際上就是struct Student的別名。
另外這里也可以不寫Student(于是也不能struct Student stu1;了)
typedef struct
{
int a;
}Stu;
struct關(guān)鍵字的一個總要作用是它可以實現(xiàn)對數(shù)據(jù)的封裝,有一點點類似與C++的對象,可以將一些分散的特性對象化,這在編寫某些復(fù)雜程序時提供很大的方便性.
比如編寫一個菜單程序,你要知道本級菜單的菜單索引號、焦點在屏上是第幾項、顯示第一項對應(yīng)的菜單條目索引、菜單文本內(nèi)容、子菜單索引、當(dāng)前菜單執(zhí)行的功能操作。若是對上述條目單獨操作,那么程序的復(fù)雜程度將會大到不可想象,若是菜單層數(shù)少些還容易實現(xiàn),一旦菜單層數(shù)超出四層,呃~我就沒法形容了。若是有編寫過菜單程序的朋友或許理解很深。這時候結(jié)構(gòu)體struct就開始顯現(xiàn)它的威力了:
//結(jié)構(gòu)體定義
typedef struct
{
unsigned char CurrentPanel;//本級菜單的菜單索引號
unsigned char ItemStartDisplay; //顯示第一項對應(yīng)的菜單條目索引
unsigned char FocusLine; //焦點在屏上是第幾項
}Menu_Statestruct;
typedef struct
{
unsigned char *MenuTxt; //菜單文本內(nèi)容
unsigned char MenuChildID;//子菜單索引
void (*CurrentOperate)();//當(dāng)前菜單執(zhí)行的功能操作
}MenuItemStruct;
typedef struct
{
MenuItemStruct *MenuPanelItem;
unsigned char MenuItemCount;
}MenuPanelStruct;
菜單程序中的結(jié)構(gòu)體定義,這個菜單程序最大可以到256級菜單。當(dāng)初要寫一個菜單程序之前,并沒有對結(jié)構(gòu)體了解多少,也沒有想到使用結(jié)構(gòu)體。只是一層層菜單的單獨處理:如果按鍵按下,判斷是哪個按鍵,調(diào)用對應(yīng)按鍵的子程序,刷屏顯示。這樣處理起來每一層都要判斷當(dāng)前的光標(biāo)所在行,計算是不是在顯示屏的頂層,是不是在顯示層的底層,是不是需要翻頁等等,非常的繁瑣。
【C語言關(guān)鍵字】相關(guān)文章:
C語言學(xué)習(xí)經(jīng)驗(精品)07-01
c語言中什么是靜態(tài)變量05-26
C語言學(xué)習(xí)經(jīng)驗[精華6篇]07-01
計算機二級C語言難不難 考什么03-05
C位的作文11-21
C羅將缺席季前賽,曼晚稱C羅獲得額外假期03-11
維生素c的故事反思07-15
為什么不看好C2C二手車電商08-14