Yeo*_*eng 2 c void-pointers qsort
我正在努力整合代码库(将qsort compar函数移动到新的标头/库,以便可以在不复制/意大利面的情况下共享它),并注意到在此过程中出现了一些奇怪的情况。
这是一个示范性清单:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/** One record has three fields.
* Each field contains a NULL terminated string of length at most 7 characters. */
typedef char Record[3][8];
int main(void)
{
Record database[5] = {0};
strcpy(database[0][0], "ZING");
strcpy(database[0][1], "BOP");
strcpy(database[0][2], "POW");
strcpy(database[1][0], "FIDDLY");
strcpy(database[1][1], "ECHO");
strcpy(database[1][2], "ZOOOM");
strcpy(database[2][0], "AH");
strcpy(database[2][1], "AAAAA");
strcpy(database[2][2], "AH");
strcpy(database[3][0], "BO");
strcpy(database[3][1], "DELTA");
strcpy(database[3][2], "FO");
strcpy(database[4][0], "FRRING");
strcpy(database[4][1], "CRASH");
strcpy(database[4][2], "FOO");
//(gdb) ptype record_compare_field_1
//type = int (char (*)[8], char (*)[8])
int record_compare_field_1();
qsort(database, 5, sizeof(Record), record_compare_field_1);
for (int i = 0; i < 5; i++){
printf("%s\t%s\t%s\n", database[i][0], database[i][1], database[i][2]);
}
}
/* Compares Records at field one. */
int record_compare_field_1(Record rowA, Record rowB)
{
return strcmp(rowA[1], rowB[1]);
}
Run Code Online (Sandbox Code Playgroud)
编译并运行:
$ gcc -Wall main.c
$ ./a.out
AH AAAAA AH
ZING BOP POW
FRRING CRASH FOO
BO DELTA FO
FIDDLY ECHO ZOOOM
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是:
compar不具有规定的函数签名,因此编译器不会发出警告int (*compar)(const void *, const void *)。即使在gdb我运行时ptype record_compare_field_1,看起来签名也不包含const *void。AAAAA, BOP, CRASH, DELTA, ECHO.问题是:
qsort compar正在使用的函数以使用正确的签名,我该怎么做(我一直在努力想出正确的转换)?谢谢你!
该int record_compare_field_1();声明没有原型。这是 C17/C18 标准的过时功能。
在函数调用中qsort(database, 5, sizeof(Record), record_compare_field_1);,record_compare_field_1参数具有类型int (*)()并且qsort参数也compar具有类型int (*)(const void *, const void *)。C17 6.2.7 中的这条规则允许这样做:
\n\n\xe2\x80\x94 如果只有一种类型是带有参数类型列表的函数类型(函数原型),则复合类型是带有参数类型列表的函数原型。
\n
实际的record_compare_field_1函数定义具有原型int record_compare_field_1(Record, Record),其中Record类型由 定义typedef char Record[3][8]。由于数组参数调整为指针,因此与原型相同int record_compare_field_1(char (*)[8], char (*)[8])。
qsort将使用错误的原型调用传入的record_compare_field_1函数,从而导致未定义的行为。大多数 C 实现对所有对象指针类型使用相同的表示形式,因此它可以让您摆脱它。
为了正确地做到这一点,该record_compare_field_1函数可以这样定义:
int record_compare_field_1(const void *a, const void *b)\n{\n const Record *p_rowA = a;\n const Record *p_rowB = b;\n return strcmp((*p_rowA)[1], (*p_rowB)[1]);\n}\nRun Code Online (Sandbox Code Playgroud)\n