Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

347
Views
qsort: ¿Transmitir la función de comparación en sí o los parámetros en el cuerpo de la función de comparación?

Hay un par de formas obvias de usar qsort : cast en el comparador:

 int cmp(const void *v1, const void *v2) { const double *d1 = v1, *d2 = v2; ⋮ } qsort(p, n, sizeof(double), cmp);

o lanzar el comparador:

 int cmp(const double *d1, const double *d2) { ⋮ } qsort(p, n, sizeof(double), (int (*)(const void *, const void *))cmp);

Tiendo a usar el primero, más por razones estéticas que otra cosa. ¿Hay alguna razón técnica para preferir uno sobre el otro?

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Debe evitar el último caso porque no es válido.

Para que dos tipos de funciones sean compatibles, los tipos de devolución deben ser compatibles y los tipos de parámetros correspondientes deben ser compatibles. Un const void * no es compatible con un const double * por lo que los tipos de función no son compatibles. Llamar a una función a través de un tipo de puntero incompatible da como resultado un comportamiento indefinido .

Tenga en cuenta que el hecho de que dos tipos se puedan convertir implícitamente no significa que sean compatibles . Tomando el ejemplo de const double * y const void * , la conversión entre los dos tipos se puede realizar sin conversión, sin embargo, la representación de los dos tipos no necesita ser la misma.

Esto significa que la forma en que se pasa una const double * a una función puede ser diferente de cómo se pasa una const void * a una función. Entonces, llamando a una función de tipo int (*)(const double*, const double*) como si tuviera tipo int (*)(const void*, const void*) , los parámetros podrían pasarse de manera incorrecta.

Si bien los sistemas x64 y ARM generalmente usarán la misma representación para todos los tipos de puntero, es posible que se salga con la suya haciendo lo primero, pero aún no hay garantía de eso. Los compiladores modernos a menudo asumen que no ocurrirá un comportamiento indefinido y realizan optimizaciones basadas en ese hecho.

El primer caso es el método adecuado ya que la firma de la función es compatible con lo que espera la función qsort .

over 4 years ago · Santiago Trujillo Report

0

Además de la excelente respuesta de dbush , se debe tener en cuenta que el caso de una función de comparación alternativa con un prototipo de int cmp(const char *s1, const char *s2) , como strcmp no es tan claro como el de la pregunta. El Estándar C especifica que:

6.2.5 Tipos

[...] Un puntero a void tendrá los mismos requisitos de representación y alineación que un puntero a un tipo de carácter. De manera similar, los punteros a versiones cualificadas o no cualificadas de tipos compatibles tendrán los mismos requisitos de representación y alineación. Todos los punteros a tipos de estructuras tendrán los mismos requisitos de representación y alineación que los demás. Todos los punteros a tipos de unión tendrán los mismos requisitos de representación y alineación que los demás. No es necesario que los punteros a otros tipos tengan los mismos requisitos de representación o alineación.

Por lo tanto, los punteros a funciones con prototipos int cmp(const void *v1, const void *v2) e int cmp(const char *v1, const char *v2) no son compatibles , pero es poco probable que la secuencia de llamada sea diferente incluso en aquellos extremadamente objetivos raros en los que int cmp(const double *v1, const double *v2) sería problemático (los primeros sistemas Cray y las CPU carecían de capacidad de direccionamiento de bytes).


No proporciona el código para las funciones de comparación: es un error común simplemente devolver la diferencia de valores ( *d1 - *d2 ). Esto no funciona para los valores de punto flotante y tampoco para los valores int , ya que la resta puede desbordarse.

Aquí hay una implementación para el orden creciente que funciona para todos los tipos de números:

 int cmp(const void *v1, const void *v2) { const int *p1 = v1, *p2 = v2; return (*p1 > *p2) - (*p1 < *p2); }

Para los tipos de coma flotante, es posible que se necesite un manejo especial de los valores de NaN:

 // sort by increasing values, with NaN after numbers int cmp(const void *v1, const void *v2) { const double *p1 = v1, *p2 = v2; if (isnan(*p1)) { return isnan(*p2) ? 0 : 1; } else if (isnan(*p2)) { return -1; } else { return (*p1 > *p2) - (*p1 < *p2); } }
over 4 years ago · Santiago Trujillo Report

0

Como apéndice, hay otra estrategia para llamar a qsort : crear una función prototipo intermedia qsort requerida que llame a una función de comparación habilitada para tipos.

 #include <stdlib.h> #include <stdio.h> static int double_cmp(const double *d1, const double *d2) { return (*d1 > *d2) - (*d2 > *d1); } static int double_void_cmp(const void *v1, const void *v2) { return double_cmp(v1, v2); } int main(void) { double p[] = { 2.18, 6.28, 3.14, 1.20, 2.72, 0.58, 4.67, 0.0, 1, 1.68 }; const size_t n = sizeof p / sizeof *p; size_t i; qsort(p, n, sizeof *p, &double_void_cmp); for(i = 0; i < n; i++) printf("%s%.2f", i ? ", " : "", p[i]); fputs(".\n", stdout); return EXIT_SUCCESS; }

Aunque esto tiene sus propios problemas, uno puede usar double_cmp como comparador para otras cosas que no son qsort . Además, no requiere moldes ni asignaciones explícitas, según mi interpretación de ISO 9899 6.3.2.3,

Un puntero a void puede convertirse en o desde un puntero a cualquier tipo de objeto o incompleto. . . y de regreso.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!