void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
有沒有辦法通過,比如說strcmp不qsort制作輔助函式?
我試圖做:
qsort(..., (int (*) (const void*, const void*) (strcmp)));
uj5u.com熱心網友回復:
您對演員表的嘗試只是有一個放錯位置的右(右)括號。最后的那個應該在演員表的型別之后。因此,您可以更改:
(int (*) (const void*, const void*) (strcmp))
// ^ wrong
到
(int (*) (const void*, const void*)) (strcmp)
// ^ right
typedef或者,雖然在別名中隱藏指標型別是非常不受歡迎的,但函式指標型別是該準則的一個例外。因此,首先為qsort比較器定義所需的型別更容易/更清晰:
typedef int (*QfnCast) (const void*, const void*);
然后,您可以轉換為該型別:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int (*QfnCast) (const void*, const void*);
int main(void)
{
char list[5][8] = {
"Fred",
"Bob",
"Anna",
"Gareth",
"Joe"
};
qsort(list, 5, 8, (QfnCast)(strcmp));
for (int i = 0; i < 5; i) printf("%s\n", list[i]);
return 0;
}
uj5u.com熱心網友回復:
int (*)(const void*, const void*)并且int (*)(const char*, const char*)是不兼容的函式指標型別。
在不同的、不兼容的函式指標型別之間進行轉換是明確未定義的行為,C17 6.3.2.3/8 強調我的:
指向一種型別的函式的指標可以轉換為指向另一種型別的函式的指標,然后再回傳;結果應與原始指標比較。如果轉換后的指標用于呼叫型別與參考型別不兼容的函式,則行為未定義。
因此,如果您strcmp轉換為其他內容,您將明確呼叫未定義的行為。它可能會在所有指標型別大小相同的任何系統上實際作業。但如果你要依賴它,你不妨做這樣的事情:
typedef union
{
int (*strcmp) (const char*, const char*);
int (*compare)(const void*, const void*);
} strcmp_t;
const strcmp_t hack = { strcmp };
...
qsort(str, x, y, hack.compare);
這就像未定義的行為(并且可能在實踐中起作用)但更具可讀性。
您永遠不能這樣做qsort(str, x, y, strcmp),因為再次strcmp與預期的函式指標型別不兼容qsort。函式引數傳遞是按賦值完成的,因此簡單賦值的規則是相關部分,從 C17 6.5.11 開始:
約束
...
- 左運算元具有原子、限定或非限定指標型別,并且(考慮左運算元在左值轉換后將具有的型別)兩個運算元都是指向兼容型別的限定或非限定版本的指標,并且左側指向的型別具有所有右邊指向的型別的限定符;
因此qsort(str, x, y, strcmp)C 總是無效的,這不是實施質量問題。相反,編譯器在沒有診斷的情況下讓它通過,這將被視為無可救藥的破壞。
最后,如評論中所述,strcmp只有在您有真正的 2D 字符陣列bsearch(qsort例如char str[x][y];. 以我的經驗,這是一個相當罕見的用例。在處理字串時,您更有可能擁有char* str[x],在這種情況下,無論如何您都必須撰寫一個包裝器strcmp。
uj5u.com熱心網友回復:
您正在嘗試做的事情有兩個問題。
首先,strcmp有型別int (*)(const char *, const char *)。此型別與int (*)(const void*, const void*)函式預期的型別不兼容,因為引數型別不兼容。這將導致通過不兼容的指標型別進行qsort呼叫strcmp,并且這樣做會觸發未定義的行為。
如果并且具有相同的表示,這可能會起作用,但不能保證會是這種情況。char *void *
第二個問題是,即使呼叫“有效”,最終傳遞給strcmp的實際上不是 achar *而是 a char **。這意味著strcmp它將嘗試讀取一個char *值,就好像它是一個char值序列一樣。
所以你必須使用輔助函式來獲得你想要的結果:
int compare(const void *a, const void *b)
{
const char **s1 = a;
const char **s2 = b;
return strcmp(*a, *b);
}
uj5u.com熱心網友回復:
正如@some程式員老兄已經說過的那樣,這取決于您要排序的內容。如果它是一個字串陣列,您可以strcmp不使用輔助函式并進行強制轉換以避免丑陋的警告:
char s_array[100][100] = { "z", "a", ... };
qsort( s_array, 100, 100, (int (*)(const void *, const void *))strcmp );
如果它是一個指標陣列,則需要一個輔助函式,因為它會傳遞指向指標的指標:
char *p_array[100] = { "z", "a", ... };
int cmp( const void *p1, const void *p2 )
{
return strcmp( *(const char **)p1, *(const char **)p2 );
}
qsort( p_array, 100, sizeof *p_array, cmp );
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/468827.html
