從語句 char* p="test" 說起
?
?
?
我相信,使用
C/C++
多年的人對下面這個字符串賦值語句都不會陌生吧。
?
????????????? char* p = “anything”;
?
同時,我也相信,各位在使用這種語句后吃過很多苦頭也不少吧?只要你想利用指針
p
來改變字符串的內(nèi)容,你的程序都會到一個讓你顏面盡失一個內(nèi)存非法操作。比如,下面的這些語句:
?
????????????? p[0] = ‘s’;
????????????? strcpy(p, “haoel”);
?
原因就在于,
char* p = “hello world”;
這個聲明,聲明了一個指針,而這個指針指向的是全局的
const
內(nèi)存區(qū)
,
const
內(nèi)存區(qū)當(dāng)然不會讓你想改就改的。所以,如果你一定要寫這塊內(nèi)存的話,那就是一個非常嚴(yán)重的內(nèi)存錯誤。另,之所以加粗“全局
const
內(nèi)存區(qū)”,是強(qiáng)調(diào)一下,如果你不信的話,你可以試試下面這段代碼,看看
p1
和
p2
的地址是不是一樣的。
?
????????????? char* p1 = “anything”;
????????????? char* p2 = “anything”;
????????????? printf(“ p1=%x, p2=%x \n”, p1, p2);
?
我想這應(yīng)該是一個眾所周知的問題吧。取而代之的,應(yīng)該是使用數(shù)組來做聲明。如:
char str[] = “hello world”;
如果現(xiàn)在還有哪本書中的
C
的示例采用了這種方式,那么你就可以把那本書撕了,如果這本書是
C++
的書話,那么你應(yīng)該把這個作者和這個出版社告上法庭,因為你不應(yīng)該容忍這種學(xué)術(shù)騙子。如果你的部門的開發(fā)人員還有人寫出這種代碼的話,如果他是
C
程序員,我想你可以在打過他的屁股后告訴他下不為例,如果他是一個
C++
程序員的話,我想你可以懷疑他是否有資格做一個
C++
程序員了。
?
??????
至于你問我為什么要對學(xué)
C++
的人那么苛刻,那是因為學(xué)過
C++
的人都知道
C++
中的
const
關(guān)鍵字的有著什么樣的權(quán)力,你也應(yīng)該知道
C++
對
const
有著無比的照顧和關(guān)愛,幾乎所有關(guān)于
C++
的書都會提到
const
這東西。所以,如果作為一個
C++
的程序員來說,如果你不知道的話,那就太說不過去了。
?
??????
我們知道,雙引號引起來的字符串是
const
的,所以,在
C++
的世界中,你應(yīng)該進(jìn)行如下的聲明才比較穩(wěn)妥:
?????????????
????????????? const char *p = “anything”;
?
這樣,當(dāng)你修改這個字符串的內(nèi)容時,編譯器會給你一個錯誤而導(dǎo)致你的程序編譯不通過,從而不會產(chǎn)生運行時的內(nèi)存錯誤。
?
??????
可問題是,像
C++
這種對類型要求很嚴(yán)格的語言來說,為什么它在編譯諸如
char *p=”anything”
程序的時候不出錯,甚至連個警告都沒有(
g++
和
vc++7
)?難道這是他的一個
bug
?我想,這應(yīng)該是對古老的
C
的一個向下兼容。因為,在
C
的世界中,這種用法太多了。
?
在
C++
中,比如:函數(shù)的參數(shù)和異常的捕獲都存在這種問題,如下所示:(因編譯器而定,在
gcc 3.4.3
版中,下例中的異常示例不能被捕獲,但
VC++6
中卻可以被捕獲)
?
?????? func( char* p) { }?? //
以這種方式調(diào)用函數(shù)
func(“abc”);
??????
?????? try { thow “exception”; } catch (char* p) { }
?
??????
這些東西,無疑會對大家是一個誤導(dǎo)。甚至讓人無所畏懼地走入其中,并自以為走入了正途。這樣看來,這種向下兼容的
C++
標(biāo)準(zhǔn),就顯得有點誤人不淺了
。
?
??????
不過好在,
C++
標(biāo)準(zhǔn)委員會早已意識到了這一點。這個
C++
的
feature
被定義為了“
Deprecated Feature
”,即“不被建議使用的特性”。意思就是,在將來,這種特性將被從
C++
中移出,于是,你目前的這種程序?qū)o法在新的
C++
編譯器上編譯通過。對于程序的可移植性來說,我們今天所寫的代碼尤其要注意這些“
Deprecated Feature
”。
?
??????
據(jù)我所知,目前
C++
中被列為“
Deprecated Feature
”如下所示(可能不準(zhǔn)確,請大家指正)
?
一、??????????
隱晦的字符串的
const
轉(zhuǎn)換。
char *p = “test”;
w_char *pw = “test”;
char p[] = “test”;
??????
把一個
const
的字符串類型轉(zhuǎn)成
non-const
的。包括指針和數(shù)組。
?
二、??????????
隱晦的類型聲明。
func() {}?? //
函數(shù)的隱晦返回類型是
int
static num;??? //
變量的隱晦類型是
int
??????
這種
feature
在
C89
中還可以使用,但在
C99
和
C++
中都被去除了。(
gcc 3.4
版本對于這種聲明會給出編譯錯誤,而
VC++6.0
會認(rèn)為這是合法的程序)
?
三、??????????
布爾變量的累加操作。
bool isConn = false;
isConn++; ???????? //
這個操作會把
isConn
變?yōu)?/span>
true
就目前而言,幾乎所有的編譯器都認(rèn)可這種操作,但這種用法也是不被建議的,終有一天會被取消。
?
四、??????????
更改父類成員的存取權(quán)限。
?
class B
{
??? protected:
??????? int i;
};
?
class D : public B
{
???? public:
??????? int i;
};
?
??????
對于這種語法,一般來說,編譯器會把了類中的那個重復(fù)的變量認(rèn)為成兩份。
也就是說,父類的和子類的各是各的。這個
feature
對于所有的編譯器來說應(yīng)該都是可以編譯通過的(連個
Warning
都沒有)。但這個
feature
也是要被廢除的。
?
五、??????????
文件中域的
static
聲明
?
static int i;
static void func()
?
??????
據(jù)說,這種舊的在
C
中的為了實現(xiàn)其作用域在本文件中的
feature
在未來的
C++
中也要被取消。
?
?
文章到這里應(yīng)該結(jié)束了,在結(jié)束之前,讓我再給大家共享一個有趣的關(guān)于
const
的例子(在網(wǎng)上看到的)
?
??? const int a = 1;
??? int *p = const_cast<int*>(&a);
??? *p = 2;
?
??? cout << “value a=”<< a << endl;
??? cout << “value *p=” <<*p << endl;
??? cout << “address a=” <<&a << endl;
??? cout << “address p=” <<p << endl;
這段代碼輸出的結(jié)果如下:
?
value a=1
value *p=2
address a=0xbff1d48c
address p=0xbff1d48c
?
地址都是一樣的,可值為什么不一樣呢?呵呵。這個問題看起來有點“學(xué)術(shù)味”過濃,不過是個好例子,可以讓你知道
C++
的一些用法和一些原理。有以下幾個方面大家可以考慮一下:
1)
const int a = 1
是不是和宏有點像,會不會被編譯器優(yōu)化了?
2)
去修改一個
const
的值,本來應(yīng)該是不對的。這可能會是向舊的
C
兼容。是否會讓編譯器產(chǎn)生未知行為?
?
所以,這個示例也告訴我們,我們應(yīng)該遵循
C++
中的
const
和
non-const
的語義,任何想要破壞這個語義的事情都會給我們帶來未知的結(jié)果。