2009-07-02 31 views
4

只是我還是這個代碼Programming Pearls是錯誤的(快速排序要2個const的空隙,不是嗎?)如果是這樣,我的解決方案嗎?道歉,只是學習...錯誤qsort函數編程珍珠?

int wordncmp(char *p, char* q) 
{ int n = k; 
    for (; *p == *q; p++, q++) 
     if (*p == 0 && --n == 0) 
      return 0; 
    return *p - *q; 
} 

int sortcmp(char **p, char **q) 
{ return wordncmp(*p, *q); 
} 
... 

qsort(word, nword, sizeof(word[0]), sortcmp); 

這是一個解決方案嗎?

int sortcmp(const void *p, const void *q) 
{ return wordncmp(* (char * const *) p, * (char * const *) q); 
} 

回答

7

第一個代碼示例可能適用於幾乎所有的編譯器和CPU;然而,如果你遵循C標準的話,這在技術上是不確定的行爲。

正如你所說,qsort()的最後一個參數是一個函數指針,它帶有const void*類型的兩個參數。 sortcmp有不同的論點。你的編譯器應該讓你一不兼容類型簽名什麼的警告。在任何情況下,演員都是從一種類型的功能執行到另一種類型的功能。

C標準規定,你可以投函數指針與不同類型的其它的函數指針,但你不能解引用和調用鑄造的函數指針。不過,如果你再投的函數指針回到原來的類型,然後調用已定義的行爲 - 它調用原來的功能。

既然你從int (*)(char**, char**)強制轉換爲int (*)(const void*, const void*),然後最終qsort()被調用的比較器功能而無需進行轉換回int (*)(char**, char**),這是不確定的行爲。

但是,由於實際上在所有體系結構中,char **const void*都以相同的方式表示,函數調用幾乎總能正常工作。

如果您想獲取定義的行爲,您必須確保您的比較器函數具有正確的類型簽名,然後您可以將參數轉換爲正確的類型。您的解決方案完全正確,並且不違反那裏的C標準。幹得好上const -correctness - 很多人不明白到底是什麼char * const *手段。

你也應該做的const char*wordncmp()帶參數,因爲你不修改參數。

附註:您也可以在技術上不是一個函數指針轉換爲數據指針(例如void*),反之亦然。該標準允許函數指針和數據指針具有不同的大小。即使它在您的計算機上正常工作,也不能保證始終有效。

+0

這個標準實際上不能保證'char *`和`void *`具有相同的表示嗎?我同意UB仍然使用錯誤的函數指針類型進行調用,但我不相信這些參數的表示是問題。問題在於,病態實現可以使用不同的調用約定來傳遞`void *`與`char *`,例如每種類型都有一組單獨的參數寄存器。 – 2012-02-20 16:13:23

2

您是對的,sortcmp的簽名與qsort的要求不符。你的更正是正確的。 wordcmp也應該被設置爲const-正確的,因爲在技術上你會丟失一些const-一路上。

int wordncmp(const char *p, const char* q)