Estaba trabajando en la consolidación de una base de código (mover una función de compar qsort a un nuevo encabezado/biblioteca para que pudiera compartirse sin ser copia/pasta) y noté algo extraño en el proceso.
Aquí hay una lista demostrativa:
#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]); }Compilar y ejecutar:
$ gcc -Wall main.c $ ./a.out AH AAAAA AH ZING BOP POW FRRING CRASH FOO BO DELTA FO FIDDLY ECHO ZOOOMMe sorprende que:
compar pasada a ordenación rápida no tiene la firma de función prescrita int (*compar)(const void *, const void *) . Incluso en gdb , cuando ejecuto ptype record_compare_field_1 , parece que la firma no contiene const *void .AAAAA, BOP, CRASH, DELTA, ECHO .Las preguntas son:
compar qsort en uso para usar la firma adecuada, ¿cómo lo haría (estuve luchando tratando de encontrar los moldes adecuados)?¡Gracias!
El int record_compare_field_1(); declaración no tiene un prototipo. Esta es una característica obsoleta del estándar C17/C18.
En la función llamar a qsort(database, 5, sizeof(Record), record_compare_field_1); , el argumento record_compare_field_1 tiene tipo int (*)() y el parámetro compar de qsort tiene tipo int (*)(const void *, const void *) . Esto está permitido por esta regla de C17 6.2.7:
— Si solo un tipo es un tipo de función con una lista de tipos de parámetros (un prototipo de función), el tipo compuesto es un prototipo de función con la lista de tipos de parámetros.
La definición real de la función record_compare_field_1 tiene el prototipo int record_compare_field_1(Record, Record) donde el tipo de Record está definido por typedef char Record[3][8] . Dado que los parámetros de matriz se ajustan a punteros, esto es lo mismo que el prototipo int record_compare_field_1(char (*)[8], char (*)[8]) .
qsort llamará a la función pasada en record_compare_field_1 con el prototipo incorrecto, lo que generará un comportamiento indefinido . La mayoría de las implementaciones de C usan la misma representación para todos los tipos de punteros de objetos, por lo que le permite salirse con la suya.
Para hacerlo correctamente, la función record_compare_field_1 podría definirse así:
int record_compare_field_1(const void *a, const void *b) { const Record *p_rowA = a; const Record *p_rowB = b; return strcmp((*p_rowA)[1], (*p_rowB)[1]); }