- 相關(guān)推薦
C++中時(shí)間與時(shí)間戳的轉(zhuǎn)換
C語言把括號、賦值、強(qiáng)制類型轉(zhuǎn)換等都作為運(yùn)算符處理。從而使C語言的運(yùn)算類型極其豐富,表達(dá)式類型多樣化。下面是小編分享的C++中時(shí)間與時(shí)間戳的轉(zhuǎn)換,一起來看一下吧。
C++ 中時(shí)間與時(shí)間戳的轉(zhuǎn)換實(shí)例
// 設(shè)置時(shí)間顯示格式:
NSString *timeStr = @"2011-01-26 17:40:50";
[formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"]; // ----------設(shè)置你想要的格式,hh與HH的區(qū)別:分別表示12小時(shí)制,24小時(shí)制。
//設(shè)置時(shí)區(qū),這個(gè)對于時(shí)間的處理有時(shí)很重要。
//例如你在國內(nèi)發(fā)布信息,用戶在國外的另一個(gè)時(shí)區(qū),你想讓用戶看到正確的發(fā)布時(shí)間就得注意時(shí)區(qū)設(shè)置,時(shí)間的換算。
//例如你發(fā)布的時(shí)間為2010-01-26 17:40:50,那么在英國愛爾蘭那邊用戶看到的時(shí)間應(yīng)該是多少呢?
//他們與我們有7個(gè)小時(shí)的時(shí)差,所以他們那還沒到這個(gè)時(shí)間呢...那就是把未來的事做了。
NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"Asia/Shanghai"];
[formatter setTimeZone:timeZone];
NSDate *date = [formatter dateFromString:timeStr]; //------------將字符串按formatter轉(zhuǎn)成nsdate
NSLog(@"date = %@", date);
NSDate *datenow = [NSDate date];//現(xiàn)在時(shí)間,你可以輸出來看下是什么格式
NSLog(@"datenow = %@", datenow);
NSString *nowtimeStr = [formatter stringFromDate:datenow];//----------將nsdate按formatter格式轉(zhuǎn)成nsstring,nsstring會顯示與當(dāng)前的時(shí)間吻合的串
NSLog(@"nowtimeStr = %@", nowtimeStr);
// 時(shí)間轉(zhuǎn)時(shí)間戳的方法:
NSString *timeSp = [NSString stringWithFormat:@"%ld", (long)[datenow timeIntervalSince1970]];
NSLog(@"timeSp:%@",timeSp); //時(shí)間戳的值
// 時(shí)間戳轉(zhuǎn)時(shí)間的方法
NSDate *confromTimesp = [NSDate dateWithTimeIntervalSince1970:1296035591];
NSLog(@"1296035591 = %@",confromTimesp);
NSString *confromTimespStr = [formatter stringFromDate:confromTimesp];
NSLog(@"confromTimespStr = %@",confromTimespStr);
// 時(shí)間戳轉(zhuǎn)時(shí)間的方法:
NSDateFormatter* formatter1 = [[NSDateFormatter alloc] init];
[formatter1 setDateStyle:NSDateFormatterMediumStyle];
[formatter1 setTimeStyle:NSDateFormatterShortStyle];
[formatter1 setDateFormat:@"yyyyMMddHHMMss"];
NSDate *date1 = [formatter1 dateFromString:@"1283376197"];
NSLog(@"date1:%@",date1);
當(dāng)前時(shí)間是:14:41:57
C/C++內(nèi)存管理
內(nèi)存分配方式
簡介
在C++中,內(nèi)存分成5個(gè)區(qū),他們分別是堆、棧、自由存儲區(qū)、全局/靜態(tài)存儲區(qū)和常量存儲區(qū)。
棧:在執(zhí)行函數(shù)時(shí),函數(shù)內(nèi)局部變量的存儲單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時(shí)這些存儲單元自動(dòng)被釋放。棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限。
堆:就是那些由 new分配的內(nèi)存塊,他們的釋放編譯器不去管,由我們的應(yīng)用程序去控制,一般一個(gè)new就要對應(yīng)一個(gè) 。如果程序員沒有釋放掉,那么在程序結(jié)束后,操作系統(tǒng)會自動(dòng)回收。
自由存儲區(qū):就是那些由malloc等分配的內(nèi)存塊,他和堆是十分相似的,不過它是用free來結(jié)束自己的生命的。
全局/靜態(tài)存儲區(qū):全局變量和靜態(tài)變量被分配到同一塊內(nèi)存中,在以前的C語言中,全局變量又分為初始化的和未初始化的,在C++里面沒有這個(gè)區(qū)分了,他們共同占用同一塊內(nèi)存區(qū)。
常量存儲區(qū):這是一塊比較特殊的存儲區(qū),他們里面存放的是常量,不允許修改。
常見的內(nèi)存錯(cuò)誤及其對策
發(fā)生內(nèi)存錯(cuò)誤是件非常麻煩的事情。編譯器不能自動(dòng)發(fā)現(xiàn)這些錯(cuò)誤,通常是在程序運(yùn)行時(shí)才能捕捉到。而這些錯(cuò)誤大多沒有明顯的癥狀,時(shí)隱時(shí)現(xiàn),增加了改錯(cuò)的難度。有時(shí)用戶怒氣沖沖地把你找來,程序卻沒有發(fā)生任何問題,你一走,錯(cuò)誤又發(fā)作了。
常見的內(nèi)存錯(cuò)誤及其對策如下:
內(nèi)存分配未成功,卻使用了它。編程新手常犯這種錯(cuò)誤,因?yàn)樗麄儧]有意識到內(nèi)存分配會不成功。常用解決辦法是,在使用內(nèi)存之前檢查指針是否為NULL。如果指針p是函數(shù)的參數(shù),那么在函數(shù)的入口處用assert(p!=NULL)進(jìn)行檢查。如果是用malloc或new來申請內(nèi)存,應(yīng)該用if(p==NULL) 或if(p!=NULL)進(jìn)行防錯(cuò)處理。
內(nèi)存分配雖然成功,但是尚未初始化就引用它。犯這種錯(cuò)誤主要有兩個(gè)起因:一是沒有初始化的觀念;二是誤以為內(nèi)存的缺省初值全為零,導(dǎo)致引用初值錯(cuò)誤(例如數(shù)組)。內(nèi)存的缺省初值究竟是什么并沒有統(tǒng)一的標(biāo)準(zhǔn),盡管有些時(shí)候?yàn)榱阒,我們寧可信其無不可信其有。所以無論用何種方式創(chuàng)建數(shù)組,都別忘了賦初值,即便是賦零值也不可省略,不要嫌麻煩。
內(nèi)存分配成功并且已經(jīng)初始化,但操作越過了內(nèi)存的邊界。例如在使用數(shù)組時(shí)經(jīng)常發(fā)生下標(biāo)“多1”或者“少1”的操作。特別是在for循環(huán)語句中,循環(huán)次數(shù)很容易搞錯(cuò),導(dǎo)致數(shù)組操作越界。
忘記了釋放內(nèi)存,造成內(nèi)存泄露。含有這種錯(cuò)誤的函數(shù)每被調(diào)用一次就丟失一塊內(nèi)存。剛開始時(shí)系統(tǒng)的內(nèi)存充足,你看不到錯(cuò)誤。終有一次程序突然死掉,系統(tǒng)出現(xiàn)提示:內(nèi)存耗盡。動(dòng)態(tài)內(nèi)存的申請與釋放必須配對,程序中malloc與free的使用次數(shù)一定要相同,否則肯定有錯(cuò)誤(new/同理)。
釋放了內(nèi)存卻繼續(xù)使用它。
有三種情況:
(1). 程序中的對象調(diào)用關(guān)系過于復(fù)雜,實(shí)在難以搞清楚某個(gè)對象究竟是否已經(jīng)釋放了內(nèi)存,此時(shí)應(yīng)該重新設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu),從根本上解決對象管理的混亂局面。
(2). 函數(shù)的return語句寫錯(cuò)了,注意不要返回指向“棧內(nèi)存”的“指針”或者“引用”,因?yàn)樵搩?nèi)存在函數(shù)體結(jié)束時(shí)被自動(dòng)銷毀。
(3). 使用free或釋放了內(nèi)存后,沒有將指針設(shè)置為NULL。導(dǎo)致產(chǎn)生“野指針”。
那么如何避免產(chǎn)生野指針呢?這里列出了5條規(guī)則,平常寫程序時(shí)多注意一下,養(yǎng)成良好的習(xí)慣。
規(guī)則1:用malloc或new申請內(nèi)存之后,應(yīng)該立即檢查指針值是否為NULL。防止使用指針值為NULL的內(nèi)存。
規(guī)則2:不要忘記為數(shù)組和動(dòng)態(tài)內(nèi)存賦初值。防止將未被初始化的內(nèi)存作為右值使用。
規(guī)則3:避免數(shù)組或指針的下標(biāo)越界,特別要當(dāng)心發(fā)生“多1”或者“少1”操作。
規(guī)則4:動(dòng)態(tài)內(nèi)存的申請與釋放必須配對,防止內(nèi)存泄漏。
規(guī)則5:用free或釋放了內(nèi)存之后,立即將指針設(shè)置為NULL,防止產(chǎn)生“野指針”。
C/C++函數(shù)調(diào)用的方式
棧是一種先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu),棧有一個(gè)存儲區(qū)、一個(gè)棧頂指針。棧頂指針指向堆棧中第一個(gè)可用的數(shù)據(jù)項(xiàng)(被稱為棧頂)。用戶可以在棧頂上方向棧中加入數(shù)據(jù),這個(gè)操作被稱為壓棧(Push),壓棧以后,棧頂自動(dòng)變成新加入數(shù)據(jù)項(xiàng)的位置,棧頂指針也隨之修改。用戶也可以從堆棧中取走棧頂,稱為彈出棧(pop),彈出棧后,棧頂下的一個(gè)元素變成棧頂,棧頂指針隨之修改。函數(shù)調(diào)用時(shí),調(diào)用者依次把參數(shù)壓棧,然后調(diào)用函數(shù),函數(shù)被調(diào)用以后,在堆棧中取得數(shù)據(jù),并進(jìn)行計(jì)算。函數(shù)計(jì)算結(jié)束以后,或者調(diào)用者、或者函數(shù)本身修改堆棧,使堆;謴(fù)原裝。
在參數(shù)傳遞中,有兩個(gè)重要的問題必須要明確說明:
1. 當(dāng)參數(shù)個(gè)數(shù)多于一個(gè)時(shí),按照什么順序把參數(shù)壓入堆棧;
2. 函數(shù)調(diào)用后,由誰來把堆;謴(fù)原狀。
在高級語言中,就是通過函數(shù)的調(diào)用方式來說明這兩個(gè)問題的。常見的調(diào)用方式有:
stdcall
cdecl
fastcall
thiscall
thiscall
naked call
下面就分別介紹這幾種調(diào)用方式:
1.stdcall
stdcall調(diào)用方式又被稱為Pascal調(diào)用方式。在Microsoft C++系列的C/C++編譯器中,使用PASCAL宏,WINAPI宏和CALLBACK宏來指定函數(shù)的調(diào)用方式為stdcall。
stdcall調(diào)用方式的函數(shù)聲明為:
int stdcall function(int a, int b);
stdcall的調(diào)用方式意味著:
(1) 參數(shù)從右向左一次壓入堆棧
(2) 由被調(diào)用函數(shù)自己來恢復(fù)堆棧
(3) 函數(shù)名自動(dòng)加前導(dǎo)下劃線,后面緊跟著一個(gè)@,其后緊跟著參數(shù)的尺寸
上面那個(gè)函數(shù)翻譯成匯編語言將變成:
push b 先壓入第二個(gè)參數(shù)
push a 再壓入第一個(gè)參數(shù)
call function 調(diào)用函數(shù)
在編譯時(shí),此函數(shù)的名字被翻譯為function@8
2.cdecl
cdecl調(diào)用方式又稱為C調(diào)用方式,是C語言缺省的調(diào)用方式,它的語法為:
int function(int a, int b) // 不加修飾符就是C調(diào)用方式
int cdecl function(int a, int b) // 明確指定用C調(diào)用方式
cdecl的調(diào)用方式?jīng)Q定了:
(1) 參數(shù)從右向左依次壓入堆棧
(2) 由調(diào)用者恢復(fù)堆棧
(3) 函數(shù)名自動(dòng)加前導(dǎo)下劃線
由于是由調(diào)用者來恢復(fù)堆棧,因此C調(diào)用方式允許函數(shù)的參數(shù)個(gè)數(shù)是不固定的,這是C語言的一大特色。
此方式的函數(shù)被翻譯為:
push b // 先壓入第二個(gè)參數(shù)
push a // 在壓入第一個(gè)參數(shù)
call funtion // 調(diào)用函數(shù)
add esp, 8 // 清理堆棧
在編譯時(shí),此方式的函數(shù)被翻譯成:function
3.fastcall
fastcall 按照名字上理解就可以知道,它是一種快速調(diào)用方式。此方式的函數(shù)的第一個(gè)和第二個(gè)DWORD參數(shù)通過ecx和edx傳遞,
后面的參數(shù)從右向左的順序壓入棧。
被調(diào)用函數(shù)清理堆棧。
函數(shù)名修個(gè)規(guī)則同stdcall
其聲明語法為:
int fastcall function(int a, int b);
4.thiscall
thiscall 調(diào)用方式是唯一一種不能顯示指定的修飾符。它是c++類成員函數(shù)缺省的調(diào)用方式。由于成員函數(shù)調(diào)用還有一個(gè)this指針,因此必須用這種特殊的調(diào)用方式。
thiscall調(diào)用方式意味著:
參數(shù)從右向左壓入棧。
如果參數(shù)個(gè)數(shù)確定,this指針通過ecx傳遞給被調(diào)用者;如果參數(shù)個(gè)數(shù)不確定,this指針在所有參數(shù)壓入棧后被壓入棧。
參數(shù)個(gè)數(shù)不定的,由調(diào)用者清理堆棧,否則由函數(shù)自己清理堆棧。
可以看到,對于參數(shù)個(gè)數(shù)固定的情況,它類似于stdcall,不定時(shí)則類似于cdecl。
5.naked call
是一種比較少見的調(diào)用方式,一般高級程序設(shè)計(jì)語言中不常見。
函數(shù)的聲明調(diào)用方式和實(shí)際調(diào)用方式必須一致,必然編譯器會產(chǎn)生混亂。
函數(shù)名字修改規(guī)則:
1.C編譯時(shí)函數(shù)名修飾約定規(guī)則:
stdcall調(diào)用約定在輸出函數(shù)名前加上一個(gè)下劃線前綴,后面加上一個(gè)“@”符號和其參數(shù)的字節(jié)數(shù),格式為function@8。
cdecl調(diào)用約定僅在輸出函數(shù)名前加上一個(gè)下劃線前綴,格式為function。
fastcall調(diào)用約定在輸出函數(shù)名前加上一個(gè)“@”符號,后面也是一個(gè)“@”符號和其參數(shù)的字節(jié)數(shù),格式為@function@8。
它們均不改變輸出函數(shù)名中的字符大小寫,這和PASCAL調(diào)用約定不同,PASCAL約定輸出的函數(shù)名無任何修飾且全部大寫。
2.C++編譯時(shí)函數(shù)名修飾約定規(guī)則:
stdcall調(diào)用約定:
(1)以“?”標(biāo)識函數(shù)名的開始,后跟函數(shù)名;
(2)函數(shù)名后面以“@@YG”標(biāo)識參數(shù)表的開始,后跟參數(shù)表;
(3)參數(shù)表以代號表示:
X--void ,
D--char,
E--unsigned char,
F--short,
H--int,
I--unsigned int,
J--long,
K--unsigned long,
M--float,
N--double,
N--bool,
PA--表示指針,后面的代號表明指針類型,如果相同類型的指針連續(xù)出現(xiàn),以“0”代替,一個(gè)“0”代
表一次重復(fù);
(4)參數(shù)表的第一項(xiàng)為該函數(shù)的返回值類型,其后依次為參數(shù)的數(shù)據(jù)類型,指針標(biāo)識在其所指數(shù)據(jù)類型前;
(5)參數(shù)表后以“@Z”標(biāo)識整個(gè)名字的結(jié)束,如果該函數(shù)無參數(shù),則以“Z”標(biāo)識結(jié)束。
其格式為“?functionname@@YG*****@Z”或“?functionname@@YG*XZ”,例如
int Test1(char *var1,unsigned long)-----“?Test1@@YGHPADK@Z”
void Test2() -----“?Test2@@YGXXZ”
cdecl調(diào)用約定:
規(guī)則同上面的stdcall調(diào)用約定,只是參數(shù)表的開始標(biāo)識由上面的“@@YG”變?yōu)椤癅@YA”。
fastcall調(diào)用約定:
規(guī)則同上面的stdcall調(diào)用約定,只是參數(shù)表的開始標(biāo)識由上面的“@@YG”變?yōu)椤癅@YI”。
VC++對函數(shù)的省缺聲明是"cedcl",將只能被C/C++調(diào)用。
關(guān)于C/C++ 表達(dá)式求值順序
i = ++i + 1; // The behavior is unspecified
在介紹概念之前,我們先解釋一下它的結(jié)果。這個(gè)表達(dá)式( expression )包含3個(gè)子表達(dá)式( subexpression ):
e1 = ++i
e2 = e1 + 1
i = e2
這三個(gè)子表達(dá)式都沒有順序點(diǎn)( sequence point ),而 ++ i 和 i = e3 都是有副作用( side effect )的表達(dá)式。由于沒有順序點(diǎn),語言不保證這兩個(gè)副作用的順序。
更加可怕的是,如果i 是一個(gè)內(nèi)建類型,并在下一個(gè)順序點(diǎn)之前被改寫超過一次,那么結(jié)果是未定義(undefined)的!比如本例中如果有:
int i = 0x1000fffe;
i = ++i + 1; // The result is undefined!!
你也許會認(rèn)為他的結(jié)果是加1 或者加2,其實(shí)更糟糕 —— 結(jié)果可能是 0x1001ffff 。他的高字節(jié)接受了一個(gè)副作用的內(nèi)容,而低字節(jié)則接受了另一個(gè)副作用的內(nèi)容! 如果i 是指針,那么將很容易造成程序崩潰。
為什么要這么做呢?因?yàn)閷τ诰幾g器提供商來說,未確定的順序?qū)?yōu)化有相當(dāng)重要的作用。比如,一個(gè)常見的優(yōu)化策略是“減少寄存器占用和臨時(shí)對象”。編譯器可以重新組織表達(dá)式的求值,以便盡量不使用額外的寄存器以及臨時(shí)變量。 更加嚴(yán)格的說,即使是編譯器提供商也無法完全徹底序列化指令(比如無法嚴(yán)格規(guī)定讀和寫的順序),因?yàn)镃PU本身有權(quán)利修改指令順序,以便達(dá)到更高的速度。
下面的術(shù)語以 ISO C99 和 C++03為準(zhǔn)。譯名為參考并附帶原術(shù)語對照,如有解釋不當(dāng)或者錯(cuò)誤望指正。
表達(dá)式有兩種功能。每個(gè)表達(dá)式都產(chǎn)生一個(gè)值( value ),同時(shí)可能包含副作用( side effect ),比如:他可能修改某些值。
規(guī)則的核心在于 順序點(diǎn)( sequence point ) [ C99 6.5 Expressions 條款2 ] [ C++03 5 Expressions 概述 條款4 ]。 這是一個(gè)結(jié)算點(diǎn),語言要求這一側(cè)的求值和副作用(除了臨時(shí)對象的銷毀以外)全部完成,才能進(jìn)入下面的部分。 C/C++中大部分表達(dá)式都沒有順序點(diǎn),只有下面五種表達(dá)式有:
1 函數(shù)。函數(shù)調(diào)用之前有一個(gè)求值順序點(diǎn)。
2 && || 和 ?: 這三個(gè)包含邏輯的表達(dá)式。其左側(cè)邏輯完成后有一個(gè)求值順序點(diǎn)。
3 逗號表達(dá)式。逗號左側(cè)有一個(gè)求值順序點(diǎn)。
注意,他們都只有一個(gè)求值順序點(diǎn),2和3的右側(cè)運(yùn)算結(jié)束后并沒有求值順序點(diǎn)。
在兩個(gè)順序點(diǎn)之間,子表達(dá)式求值和副作用的順序是不確定的。假如代碼的結(jié)果與求值和副作用發(fā)生順序相關(guān),我們稱這樣的代碼有不確定的行為(unspecified behavior)。 而且,假如期間對一個(gè)內(nèi)建類型執(zhí)行一次以上的寫操作,則是未定義行為(undefined behavior)——我們知道,未定義行為帶來最好的后果是讓你的程序立即崩掉。
n = n++; // 兩個(gè)副作用,對于內(nèi)建對象產(chǎn)生是未定義行為
幾乎所有表達(dá)式,求值順序都不確定。比如,下面的加法, f1 f2 f3的調(diào)用順序是任意的:
n = f1() + f2() + f3(); // f1 f2 f3 調(diào)用順序任意
而函數(shù)也只在實(shí)際調(diào)用前有一個(gè)求值順序點(diǎn)。所以,常見于早期 C 語言教材的這類題目,是錯(cuò)題:
printf("%d",--a+b,--b+a); // --a + b 和 --b + a 這兩個(gè)子表達(dá)式,求值順序不確定
天啊,甚至可能出現(xiàn)未定義行為?那么堅(jiān)決不寫與實(shí)現(xiàn)相關(guān)的代碼是最好的對策。即使是不確定行為(比如函數(shù)調(diào)用時(shí)) 只要沒有順序點(diǎn)編譯器怎么做方便就怎么做。 有些人認(rèn)為函數(shù)調(diào)用參數(shù)求值與入棧順序相關(guān),這是一種誤導(dǎo)。這個(gè)東西要解釋,無異于事后諸葛亮:
void f( int i1, int i2, int i3, int i4 ){
cout<< i1 << ' ' << i2 << ' ' << i3 << ' ' << i4 << endl;}
int main(){
int i = 0;
f( i++, i++, i++, i++ );}
這個(gè)有四個(gè)表達(dá)式求值,同時(shí)每個(gè)表達(dá)式都有負(fù)作用。這八個(gè)操作順序是任意的,那么結(jié)果如何?未定義。
請用 VC7.1 Debug和 Release 分別測試這同一份代碼,結(jié)果是不同的:
0 0 0 0 [release]
3 2 1 0 [debug]
事實(shí)上,鑒于前面的討論,如果換一些其他初始值,這里甚至?xí)霈F(xiàn)錯(cuò)位而得到千奇百怪的詭異結(jié)果。
再看看C/C++標(biāo)準(zhǔn)中的其他經(jīng)典例子:
[C99] 6.5.2.2 Function call
條款12 EXAMPLE 在下面的函數(shù)調(diào)用中:
(*pf[f1()]) ( f2(), f3() + f4() )
函數(shù) f1 f2 f3 和f4 可能以任何順序被調(diào)用。 但是,所有副作用都必須在那個(gè) pf[ f1() ] 返回的函數(shù)指針產(chǎn)生的調(diào)用前完成。
[C++03] 5 Expressions 概論4
i = v[i++]; // the behavior is unspecified
i = 7, i++, i++; // i becomes 9 ( 譯注: 賦值表達(dá)式比逗號表達(dá)式優(yōu)先級高 )
i = ++i + 1; // the behavior is unspecified
i = i + 1; // the value of i is incremented
More Effective C++ 告誡我們, 千萬不要重載 &&, || 和, 操作符[ MEC ,條款7 ]。為什么?
以逗號操作符為例,每個(gè)逗號左側(cè)有一個(gè)求值順序點(diǎn)。假如ar是一個(gè)普通的對象,下面的做法是無歧義的:
ar[ i ], ++i ;
但是,如果ar[ i ] 返回一個(gè) class A 對象或引用,而它重載了 operator, 那么結(jié)果不妙了。那么,上面的語句實(shí)際上是一個(gè)函數(shù)調(diào)用:
ar[ i ].operator, ( ++i );
C/C++ 中,函數(shù)只在調(diào)用前有一個(gè)求值順序點(diǎn)。所以 ar[i] 和 ++i 的求值、以及 ++i 副作用的順序是任意的。這會引起混亂。
更可怕的是,重載 && 和 || 。 大家已經(jīng)習(xí)慣了其速死算法: 如果左側(cè)求值已經(jīng)決定了最終結(jié)果,則右側(cè)不會被求值。而且大家很依賴這個(gè)行為,比如是C風(fēng)格字符串拷貝常常這樣寫:
while( p && *p )
*pd++ = *p++;
假如p 為 0, 那么 *p 的行為是未定義的,可能令程序崩潰。 而 && 的求值順序避免了這一點(diǎn)。 但是,如果我們重載 && 就等于下面的做法:
exp1 .operator && ( exp2 )
現(xiàn)在不僅僅是求值混亂了。無論exp1是什么結(jié)果,exp2 必然會被求值。
C與C++的變量聲明
如何理解C和C++的復(fù)雜類型聲明,曾經(jīng)碰到過讓你迷惑不解、類似于int * (* (*fp1) (int) );這樣的變量聲明嗎?本文將由易到難,一步一步教會你如何理解這種復(fù)雜的C/C++ 聲明,我們將從天天都能碰到的較簡單的聲明入手,然后逐步加入const修飾符和typedef,還有函數(shù)指針,最后介紹一個(gè)能夠讓你準(zhǔn)確地理解任何C/C++ 聲明的“右左法則”,需要強(qiáng)調(diào)一下的是,復(fù)雜的C/C++ 聲明并不是好的編程風(fēng)格;我這里僅僅是教你如何去理解這些聲明。注重:為了保證能夠在同一行上顯示代碼和相關(guān)注釋,本文最好在至少1024x768分辨率的顯示器上閱讀。
讓我們從一個(gè)非常簡單的例子開始,如下:
int n;
這個(gè)應(yīng)該被理解為www.diannao114.cn “declare n as an int”(n是一個(gè)int型的變量)。接下去來看一下指針變量,如下:
int *p;
這個(gè)應(yīng)該被理解為“declare p as an int *”(p是一個(gè)int *型的變量),或者說p是一個(gè)指向一個(gè)int型變量的指針。我想在這里展開討論一下:我覺得在聲明一個(gè)指針(或引用)類型的變量時(shí),最好將*(或 &)寫在緊靠變量之前,而不是緊跟基本類型之后。這樣可以避免一些理解上的誤區(qū),比如:
int* p;//不推薦
再來看一個(gè)指針的指針的例子:
char **argv;
理論上,對于指針的級數(shù)沒有限制,你可以定義一個(gè)浮點(diǎn)類型變量的指針的指針的指針的指針,再來看如下的聲明:
int RollNum[30][4];
int (*p)[4]=RollNum;
int *q[5];
這里,p被聲明為一個(gè)指向一個(gè)4元素(int類型)數(shù)組的指針,而q被聲明為一個(gè)包含5個(gè)元素(int類型的指針)的數(shù)組。另外,我們還可以在同一個(gè)聲明中混合實(shí)用*和&,如下:
int **p1;// p1 is a pointer to a pointer to an int.
int *&p2;// p2 is a reference to a pointer to an int.
int &*p3;// ERROR: Pointer to a reference is illegal.
int &&p4;// ERROR: Reference to a reference is illegal.
注:p1是一個(gè)int類型的指針的指針;p2是一個(gè)int類型的指針的引用;p3是一個(gè)int類型引用的指針(不合法。;p4是一個(gè)int類型引用的引用(不合法。。
const 修飾符
當(dāng)你想阻止一個(gè)變量被改變,可能會用到const要害字。在你給一個(gè)變量加上const修飾符的同時(shí),通常需要對它進(jìn)行初始化,因?yàn)橐院蟮娜魏螘r(shí)候你將沒有機(jī)會再去改變它。例如:
const int n=5;
int const m=10;
上述兩個(gè)變量n和m其實(shí)是同一種類型的變量,都是const int(整形恒量)。因?yàn)镃 標(biāo)準(zhǔn)規(guī)定,const要害字放在類型或變量名之前等價(jià)的。我個(gè)人更喜歡第一種聲明方式,因?yàn)樗怀隽薱onst修飾符的作用。當(dāng)const與指針一起使用時(shí),輕易讓人感到迷惑。例如,我們來看一下下面的p和q的聲明:
const int *p;
int const *q;
他們當(dāng)中哪一個(gè)代表const int類型的指針(const直接修飾int),哪一個(gè)代表int類型的const指針(const直接修飾指針)?實(shí)際上,p和q都被聲明為const int類型的指針。而int類型的const指針應(yīng)該這樣聲明:
int * const r= &n;// n has been declared as an int
這里,p和q都是指向const int類型的指針,也就是說,你在以后的程序里不能改變*p的值。而r是一個(gè)const指針,它在聲明的時(shí)候被初始化指向變量n(即r=&n;)之后,r的值將不再答應(yīng)被改變(但*r的值可以改變)。
組合上述兩種const修飾的情況,我們來聲明一個(gè)指向 const int類型的const指針,如下:
const int * const p=&n// n has been declared as const int
下面給出的一些關(guān)于const的聲明,將幫助你徹底理清const的用法。不過請注重,下面的一些聲明是不能被編譯通過的,因?yàn)樗麄冃枰诼暶鞯耐瑫r(shí)進(jìn)行初始化。為了簡潔起見,我忽略了初始化部分;因?yàn)榧尤氤跏蓟a的話,下面每個(gè)聲明都將增加兩行代碼。
char **p1;// pointer to pointer to char
const char **p2;// pointer to pointer to const char
char * const * p3;// pointer to const pointer to char
const char * const * p4;// pointer to const pointer to const char
char ** const p5;// const pointer to pointer to char
const char ** const p6;// const pointer to pointer to const char
char * const * const p7;// const pointer to const pointer to char
const char * const * const p8;// const pointer to const pointer to const char
注: p1是指向char類型的指針的指針;p2是指向const char類型的指針的指針;p3是指向char類型的const指針;p4是指向const char類型的const指針;p5是指向char類型的指針的const指針;p6是指向const char類型的指針的const指針;p7是指向char類型const指針的const指針;p8是指向const char類型的const指針的const指針。
【C++中時(shí)間與時(shí)間戳的轉(zhuǎn)換】相關(guān)文章:
PHP時(shí)間轉(zhuǎn)換Unix時(shí)間戳代碼08-19
如何利用PHP時(shí)間轉(zhuǎn)換Unix時(shí)間戳代碼10-21
php日期轉(zhuǎn)時(shí)間戳 指定日期轉(zhuǎn)換成時(shí)間戳09-26
php時(shí)間戳與日期如何轉(zhuǎn)換09-30
解析php時(shí)間戳與日期的轉(zhuǎn)換10-21
php實(shí)現(xiàn)兼容2038年后Unix時(shí)間戳轉(zhuǎn)換函數(shù)09-26
C++類的轉(zhuǎn)換10-17