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