2013-07-02 264 views
0

我正在編寫一些C代碼作爲C++,並遇到了令我困惑的東西。考慮從LuaFileSystem採取的以下功能。static char * vs static char []內存訪問

static const char *perm2string (unsigned short mode) { 
    static char perms[10] = "---------"; 
    //static char* perms = "---------"; 
    int i; 
    for (i=0;i<9;i++) perms[i]='-'; 
    if (mode & _S_IREAD) 
    { perms[0] = 'r'; perms[3] = 'r'; perms[6] = 'r'; } 
    if (mode & _S_IWRITE) 
    { perms[1] = 'w'; perms[4] = 'w'; perms[7] = 'w'; } 
    if (mode & _S_IEXEC) 
    { perms[2] = 'x'; perms[5] = 'x'; perms[8] = 'x'; } 
    return perms; 
} 

此代碼將正常工作,但是如果我取消對註釋行的註釋,它會崩潰。我用一個調試器來解決這個問題,看起來static char* perms這個字符串被放置在只讀內存中,所以第一個循環會導致訪問衝突,使用靜態數組不會導致這樣的問題。我很好奇爲什麼這是在字符串沒有被聲明爲const時發生的。

+0

'「---------」'是一個_string literal_。它是一個10 ** const ** chars_(9' - '加上「null終止符」)的_static數組,它是_immutable_。你可以用'const char * p =「---------」;'獲得一個指向它的第一個字符的指針,但是如果你想修改它,你必須將它拷貝到一個單獨的數組中('perms'例)。 –

+0

>此代碼將正常工作... 直到您同時使用它。當多個線程試圖訪問這個靜態字符串/數組時,你會得到奇怪的行爲。由於你的代碼只有8種不同的條件,所以你可以很好地使用開關/外殼查找,併爲每個返回一個預定義的字符串文字:'switch(mode){case 0:return「---------」; case _S_IREAD:return「r - r - r--」;/* etc ... * /}'這樣的函數是隻讀的,線程安全的,並且可能比char數組更快地擺脫現在的操作。 –

回答

3

沒錯。

字符串文字是不可變"---------"是一個字符串文字。您的static char*指向該字符串文字。

不變性在編譯時不是固有的,所以當你試圖寫入文字時,你會得到未定義的行爲。這可能會導致運行時崩潰。

[C++11: 2.14.5/12]:是否所有字符串文字都是不同的(即存儲在非重疊對象中)是實現定義的。 嘗試修改字符串文字的效果未定義。

C++實際上需要的是這個指針是一個static char const*,儘管一些編譯器只警告有關。

然而,初始化一個數組字符串文字意願複製的字符串。陣列是你自己的,可以隨你做。這就是爲什麼你可以修改static char[10]而不會崩潰。

[C++11: 8.5.2/1]:字符數組(無論是純charsigned char,或unsigned charchar16_t陣列,char32_t陣列或wchar_t陣列可以由窄字符文字進行初始化,char16_t字符串文字,char32_t字符串文字或寬字符串字面值,或者用大括號中的適當類型的字符串字面值。 字符串字面值的連續字符初始化數組的元素。

+0

感謝規範引號,我想我是依靠編譯器來警告我這件事(MSVC2010甚至沒有給我一個警告 - 牆集) – user1520427

+1

@ user1520427:'-Wall'更像'-Wsome' 。同樣使用'-Wextra'和'-pedantic'(對於GCC;不確定VS) –

+5

@Shahbaz:關於使用Stack Overflow _edit_函數來改善我的答案併爲OP增加價值有什麼「骯髒」?我不是第一個答案;事實上,我只比你們早6秒。在投擲惡毒指控之前請檢查您的事實。你是否建議在82K時,我應該被迫停止比賽? –

2

字符串文字存儲在內存的只讀部分。任何修改字符串文字內容的嘗試都會在大多數實現上調用未定義的行爲和分段錯誤。 所以如果你需要一個可修改的字符數組,然後聲明它爲char perms[10]而不是char* perms

2

當你寫:

const char *X = "...." 

您在只讀存儲器"...."X指向它。實際上,X的類型應該是const char *,而不僅僅是char *

在另一方面,當寫:

char X[] = "...." 

這相當於:

char X[] = {'.', '.', '.', '.', '\0'} 

這是一個數組初始化。換句話說,X將是一個數組(不是指針),它將包含"...."的內容。由於它不是const,所以可以毫無問題地更改它。

+0

我的回答有問題嗎?我很感激來自反對者的反饋。 – Shahbaz

2

字符串文字是const char *。您不允許使用C++或C修改它們。

由於遺留原因,它們可以轉換爲char *,但是這並不能使其修改爲合法。

0

這是正常的,與C++無關(你將與C有相同的結果)。 static char* perms = "---------";是常量,因爲"---------"是你的二進制文件的一部分(你可以看到它與objdump PROGRAMM)

+0

不要混淆「不變性」的常量。 –

0

char* perms = "-----"創建一個指針指向字符串,它坐落在一個受保護的部分。試圖寫入它會導致崩潰。

char perms[] = "-----"在堆棧上創建一個字符數組,並用「-----」中的相關字符填充它。這是一個數組和指針不等價的例子。