2012-01-31 72 views
13

想象我有這個C函數(在頭文件中的相應的原型)它是未定義行爲來拋棄函數參數的常量嗎?

void clearstring(const char *data) { 
    char *dst = (char *)data; 
    *dst = 0; 
} 

有沒有在上面的代碼中未定義行爲,鑄造const,或者是它只是一個非常不好的編程習慣?

假設有沒有const限定對象使用

char name[] = "pmg"; 
clearstring(name); 
+2

如果演員陣容不是UB,我認爲它應該是:) – pmg 2012-01-31 11:55:28

+0

你當然有你的腳在霰彈槍的景點! – 2012-01-31 11:57:56

+1

@pmg:如果轉換本身是UB,那麼語言允許的話就沒有什麼意義了 - 編譯器很容易檢測到const已經被添加到了轉換中,就像它檢測到'char * dst = data;'是非法的。顯然有一些沒有意義的事情是由於歷史原因標準允許的,但我聲稱這不是其中之一:-) – 2012-01-31 12:08:30

回答

20

的嘗試寫入*dst是UB 如果調用者傳遞你指向一個const對象,或指向一個字符串。

但是,如果調用者向您傳遞指向實際上可變的數據的指針,則會定義行爲。創建指向可修改的const char*char不會使該不可變的char

所以:

char c; 
clearstring(&c); // OK, sets c to 0 
char *p = malloc(100); 
if (p) { 
    clearstring(p); // OK, p now points to an empty string 
    free(p); 
} 
const char d = 0; 
clearstring(&d); // UB 
clearstring("foo"); // UB 

也就是說,你的功能是非常不明智的,因爲它是那麼容易讓呼叫者引起UB。但實際上可以將其與定義的行爲一起使用。

+4

+1:(im)可變性是對象本身的固有屬性,無論是否具有用於訪問它的指針... – Christoph 2012-01-31 12:01:58

+0

因爲「C99 6.6§9」還是因爲「C99 6.7.3§5」,這是UB嗎? – Lundin 2012-01-31 14:13:43

+1

@Lundin:後者(在字符串的情況下,6.4.5/6而不是6.7.3/5,因爲字符串文本不是C中的'const'對象)。地址常量與此無關。 – 2012-01-31 14:24:55

0

考慮一個函數,如strstr,如果給定一個指向包含字符串的對象的一部分的指針,並返回一個指向同一對象的可能不同部分的指針。如果該方法傳遞一個指向內存只讀區域的指針,它將返回一個指向內存只讀區域的指針;同樣,如果給它一個指向可寫區域的指針,它將返回一個指向可寫區域的指針。

當給定const char *時,C無法讓函數返回const char *,並且在給定普通char *時返回普通char *。爲了兼容strstr在將const char *的想法添加到語言之前工作,必須將const限定指針轉換爲非const限定指針。儘管確實如此,即使用戶代碼不能,庫函數strstr也許有權做這樣的投射,但在用戶代碼中經常出現相同的模式,以至於禁止它是實際的。