我相信,使用C/C++多年的人對下面這個字符串賦值語句都不會陌生吧。
char* p = "test";
同時,我也相信,各位在使用這種語句後吃過不少苦頭也很多吧?只要你想利用指針p來改變字符串的內容,你的程序都會獲得一個讓你顏面盡失一個內存非法操做。好比,下面的這些語句:
p[0] = 's';
strcpy(p, "haoel");
緣由就在於,char* p = "test"; 這個聲明,聲明瞭一個指針,而這個指針指向的是全局的const內存區,const內存區固然不會讓你想改就改的。因此,若是你必定要寫這塊內存的話,那就是一個很是嚴重的內存錯誤。另,之因此加粗「全局const內存區」,是強調一下,若是你不信的話,你能夠試試下面這段代碼,看看p1和p2的地址是否是同樣的。
char* p1 = "anything";
char* p2 = "anything";
printf(「 p1=%x, p2=%x /n」, p1, p2);
我想這應該是一個衆所周知的問題吧。取而代之的,應該是使用數組來作初始化聲明。如:char str[] = 「hello world」; 若是如今還有哪本書中的C的示例採用了使用const字符串初始化指針的這種方式,那麼你就能夠把那本書撕了,若是這本書是C++的書話,那麼你應該把這個做者和這個出版社告上法庭,由於你不該該容忍這種學術騙子。若是你的部門的開發人員還有人寫出這種代碼的話,若是他是C程序員,我想你能夠在打過他的屁股後告訴他下不爲例,若是他是一個C++程序員的話,我想你能夠懷疑他是否有資格作一個C++程序員了。
至於你問我爲何要對學C++的人那麼苛刻,那是由於學過C++的人都知道C++中的const關鍵字的有着什麼樣的權力,你也應該知道C++對const有着無比的照顧和關愛,幾乎全部關於C++的書都會提到const這東西。因此,若是做爲一個C++的程序員來講,若是你不知道的話,那就太說不過去了。
咱們知道,雙引號引發來的字符串是const的,因此,在C++的世界中,你應該進行以下的聲明才比較穩妥:
const char *p = "test";
這樣,當你修改這個字符串的內容時,編譯器會給你一個錯誤而致使你的程序編譯不經過,從而不會產生運行時的內存錯誤。
可問題是,像C++這種對類型要求很嚴格的語言來講,爲何它在編譯諸如char *p="test" 程序的時候不出錯,甚至連個警告都沒有(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++編譯器默認了能夠把const char* 轉成 char* 的罪行,無疑會對你們是一個誤導。甚至讓人無所畏懼地走入其中,並自覺得走入了正途。這樣看來,這種向下兼容的C++標準,就顯得有點誤人不淺了。
不過好在,C++標準委員會早已意識到了這一點。這個C++的feature被定義爲了「Deprecated Feature」,即「不被建議使用的特性」。意思就是,在未來,這種特性將被從C++中移出,因而,你目前的這種程序將沒法在新的C++編譯器上編譯經過。對於程序的可移植性來講,咱們今天所寫的代碼尤爲要注意這些「Deprecated Feature」。
據我所知,目前C++中被列爲「Deprecated Feature」以下所示(可能不許確,請你們指正)下面的這些feature都已被C++標準委員會訂爲廢除featrue了。
1、
隱晦的字符串的
const
轉換。
char *p = "test";
w_char *pw = L"test";
把一個const的字符串類型轉成non-const的。包括指針和數組。
2、
隱晦的類型聲明。
func() {} //函數的隱晦返回類型是int
static num; //變量的隱晦類型是int
這種feature在C89中還可使用,但在C99和C++中都被去除了。(gcc 3.4版本對於這種聲明會給出編譯錯誤,而VC++6.0會認爲這是合法的程序)
3、
布爾變量的累加操做。
bool isConn = false;
isConn++; //這個操做會把isConn變爲true
就目前而言,幾乎全部的編譯器都承認這種操做,但這種用法也是不被建議的,終有一天會被取消。
4、
更改父類成員的存取權限。
class B
{
protected:
int i;
};
class D : public B
{
public:
B::i; //這種方式可能你們不多看到。
};
對於這種語法,子類從新暴露了父類的私有成員。這會帶來很大的安全性問題。目前而言,這個feature對於全部的編譯器來講應該都是能夠編譯經過的(連個Warning都沒有)。但這個feature也是要被廢除的。
5、
文件中域的
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的語義,任何想要破壞這個語義的事情都會給咱們帶來未知的結果。c++