2010-07-20 76 views
1

當您使用以下標誌進行編譯時,如果添加/ GF-或刪除opimization標誌,它們不會崩潰,下面的代碼在VS 2010中崩潰。崩潰發生在彙編代碼翻譯'if(path [i] =='/')'。我喜歡理解編譯器在這裏做的優化,並導致崩潰。期待一些提示。VS2010 C代碼 - 字符串池

-Karthik

cl.exe /MD /O2 test.c

// TEST.C

#include <stdio.h> 

#include <string.h> 

void testpath(char* path, int bufsiz) 
{ 

    int i; 

    printf("%p\n", path); 
    for(i=0; i < strlen(path); i++) { 
     if(path[i] == '/') { 
     path[i] = '\\'; 
    } 
    } 
} 

int main() 
{ 

    const char* path = "testexport.prj"; 
    char *path1 = "testexport.prj"; 
    printf("%p\n", path); 
    printf("%p\n", path1); 
    testpath(path, 1024); 
} 
+0

你說這崩潰了。有沒有額外的信息說明它爲什麼崩潰?你展示的代碼不應該有任何問題。正如你所說,條件應該阻止執行任務,因爲在傳遞給函數的'path'中沒有''/''字符。你確定你在這裏展示的代碼是你正在運行的代碼的精確副本嗎? – 2016-03-03 20:17:00

回答

5

您嘗試修改字符串文字,這是不確定的行爲。

const char* path = "testexport.prj"; 
testpath(path, 1024); 
// then later: 
void testpath(char* path, int bufsiz) 
{ 
    int i; 
    for(i=0; i`<`strlen(path); i++) { 
    if(path[i] == '/') { 
     path[i] = '\\';// <<<<<< UB here 
    } 
} 

字符串字面量通常存儲在只讀存儲器中,這樣您的實施,試圖在訪問衝突崩潰程序修改字符串文字的結果。

+0

感謝您的回覆。我明白修改「字符串」字面意思會導致未指定的行爲。但是我的觀點是,當字符串文字因代碼中的條件檢查'path [i] =='/''而未被修改時,爲什麼優化的構建會導致崩潰。你能評論一下嗎? – Kartlee 2010-07-22 16:09:36

+0

@Kartlee:當進行優化時,您無法確定在調試時哪一行,因此最可能的解釋是您誤解了調試會話的結果。確定修改if語句:if(path [i] =='/'){printf(「gonna modify \ n」);路徑[i] ='\\'; }以便在修改嘗試之前有一個調試打印。我很確定程序會在修改嘗試後崩潰。 – sharptooth 2010-07-23 05:41:07

+0

但是在他顯示的代碼中,他傳遞給函數的'path'中沒有'/ /'字符。所以無論是編譯器中有一個非常奇怪的錯誤,還是他沒有告訴我們的東西。 – 2016-03-03 20:18:43

7

試圖修改​​的內容會調用未定義的行爲。

從ISO C99(Section 6.4.5/6

它是unspeci音響ED這些陣列是否是不同的條件是它們的元素具有適當的值。 如果程序試圖修改這樣的陣列,該行爲是理解過程音響定義

從ISO C++ - 98(Section 2.13.4/2

是否所有字符串文字是不同的(即,被存儲在非重疊對象)是實現定義的。 嘗試修改字符串文字的效果未定義。

在大多數實現(包括MSVC)上,這會導致應用程序崩潰。

+0

感謝您的回覆。我明白修改「字符串」字面意思會導致未指定的行爲。但是我的觀點是,當字符串文字因代碼中的條件檢查'path [i] =='/''而未被修改時,爲什麼優化的構建會導致崩潰。你能評論一下嗎? – Kartlee 2010-07-22 16:09:05

+0

@Kartlee:path [i] ='\\';試圖修改字符串文字的內容,這會導致應用程序崩潰,並且行爲是未定義的(未指定)。 :)條件檢查就好了恕我直言。 – 2010-07-22 16:27:10

+0

當沒有輸入由於條件檢查而修改它的代碼的字符串文字將導致崩潰時,這真令人吃驚。你有沒有機會看到彙編代碼在這裏發生了什麼?如果關閉字符串池,它們不會導致崩潰。我懷疑編譯器是否有任何前瞻來檢查字符串文字是否在字符串池打開時被修改。 – Kartlee 2010-07-22 17:00:38

-1

我們有一個應用程序,在VC6.0中似乎有一個字符串池中的錯誤。兩個不同的字符串似乎「彙集」爲一個字符串,導致崩潰。 VS2010中不會發生這種崩潰。或者如果/ VS用於VS6.0而不是/ ZI。只是想知道VS6.0中的默認是使用字符串池而不是VS2010中的默認值。在這種情況下,字符串池錯誤仍然存​​在。如果有許多接近完全相同的字符串,我有(尚未被審查)的工作理論是在字符串池中未檢測到散列衝突,從而消除了兩個字符串中的一個。在查看兩個幾乎相似的字符串的指針時,這將在生成的ASM代碼中可見。 在我們的例子中,我們沒有修改VC6.0中的字符串,只是引用它們。

+0

如果您有新問題,請點擊[問問題](http://stackoverflow.com/questions/ask)按鈕。如果有助於提供上下文,請包含此問題的鏈接。 - [發表評論](/ review/low-quality-posts/10887694) – Oz123 2016-01-14 19:21:44

+0

我需要分享一個案例我們有一個龐大的客戶羣,超過12年以上使用VS6.0 C++,我看到兩個應用程序實例到字符串池。我們使用 - >名稱值創建對象。我們提供了一個「find_object(」String「)」API來按名稱搜索對象。使用字符串池時,已經觀察到兩種情況,其中對象「StringA」和「StringB」都被創建並存在,但是因爲字符串對象已經過優化,所以它與原始字符串不匹配,因此無法通過搜索找到對象「StringB」。生成的* .asm顯示已優化的字符串。 TBD消毒所以我可以分享。 – 2018-01-25 22:43:21