Frage

Es gibt folgende Erklärungen:

void qsort(void *lineptr[], int left, int right, int (*comp)(void *, void *));
int numcmp(char *, char *);
int strcmp(char *s, char *t);

Dann irgendwo im Programm gibt es den folgenden Aufruf:

  qsort((void**) lineptr, 0, nlines-1, 
                    (int (*)(void*,void*))(numeric ? numcmp : strcmp));

(Ignorieren Sie die ersten drei Argumente und numeric).

ich fragen, was das ist:

(int (*)(void*,void*))(numeric ? numcmp : strcmp)

Ich verstehe, dass qsort einen „Zeiger auf Funktion, die zwei void Zeiger und gibt eine int bekommt“ erwartet, wie es der 4. Argument ist aber wie das, was oben geschrieben erfüllt ist das? Es scheint mir eine Art Guss mag, weil es aus zwei Klammern hergestellt, aber das wäre eine sehr seltsame Besetzung sein. Da dauert es eine Funktion und macht diese Funktion ein „Zeiger auf Funktion, die zwei void Zeiger und gibt eine int bekommt“. Welches ist sinnlos.
(Ich folgte hier die Regel, dass eine Art type in Klammern vor einer Variablen auf diese Art die Variable fördert).

Also ich denke, ich es einfach falsch, vielleicht kann mir jemand sagen, wie das lesen, was ist der Auftrag?

War es hilfreich?

Lösung

Was passiert hier ist in der Tat eine Besetzung. Hiermit kann der ternäre für eine zweite ignorieren und so tun, dass numcmp immer verwendet wird. Für die Zwecke dieser Frage können Funktionen als Funktionszeiger in C handeln Also, wenn Sie auf die Art der numerischen aussehen es tatsächlich ist

(int (*)(int*,int*))

Damit dies richtig in qsort verwendet werden für nichtig Parameter haben muss. Da die Typen hier alle die gleiche Größe in Bezug auf Parameter und Rückgabetypen haben, ist es möglich, dass die andere zu ersetzen, auf. Alles, was benötigt wird ist ein gegossenes der Compiler glücklich zu machen.

(int (*)(void*,void*))(numcmp )

Andere Tipps

Sie haben den Trick verpasst - der Teil

(numeric ? numcmp : strcmp)

wird den ternären Operator wählen die Funktion wird innerhalb von qsort genannt. Wenn die Daten numerisch ist, verwendet es numcmp. Wenn nicht, verwendet es strcmp. Eine lesbare Implementierung würde wie folgt aussehen:

int (*comparison_function)(void*,void*) = 
    (int (*)(void*,void*))(numeric ? numcmp : strcmp);
qsort((void**) lineptr, 0, nlines-1, comparison_function);

Sie können es ohne die Funktionszeiger Guss tun. Hier wie . Nach meiner Erfahrung in den meisten Orten, wenn Sie eine Besetzung verwenden, tun Sie es falsch.

Beachten Sie, dass die Standard-Definition von qsort() umfasst const:

void qsort(void *base, size_t nmemb, size_t size,
           int (*compar)(const void *, const void *));

Beachten Sie, dass die Zeichenfolge Komparator gegeben wird zwei ‚char **‘ Werte, nicht ‚char *‘ Werte.

Ich schreibe meine Komparatoren so dass Abgüsse unnötig in dem anrufenden Code sind:

#include <stdlib.h>    /* qsort() */
#include <string.h>    /* strcmp() */

int num_cmp(const void *v1, const void *v2)
{
    int i1 = *(const int *)v1;
    int i2 = *(const int *)v2;
    if (i1 < i2)
        return -1;
    else if (i1 > i2)
        return +1;
    else
        return 0;
}

int str_cmp(const void *v1, const void *v2)
{
    const char *s1 = *(const char **)v1;
    const char *s2 = *(const char **)v2;
    return(strcmp(s1, s2));
}

Menschen zwingen schreiben Abgüsse in dem Code mit Ihren Funktionen hässlich ist. Dies nicht tun.

Die beiden Funktionen Ich schrieb den Funktionsprototyp von der Norm qsort() erforderlich entsprechen. Der Name einer Funktion, wenn sie nicht durch Klammern entsprechen einen Zeiger auf die Funktion.

Sie in älterem Code finden, oder Code von denen geschrieben, die auf älteren Compiler erzogen wurden, dass Zeiger auf Funktionen verwendet werden, mit der Notation:

result = (*pointer_to_function)(arg1, arg2, ...);

In der modernen Stil, das steht geschrieben:

result = pointer_to_function(arg1, arg2, ...);

Ich persönlich finde die explizite Dereferenzierung klarer, aber nicht alle sind sich einig.

Wer schrieb, dass Code-Schnipsel zu klug zu sein versucht, . In seinem Kopf, denkt er wohl er, indem sie einen klugen „Einzeiler“ ein guter Programmierer zu sein. In Wirklichkeit macht er Code, weniger lesbar ist und ist widerwärtig mit langfristig zu arbeiten und soll in einer offensichtlichen Form ähnlich wie Harper Shelby Code neu geschrieben werden.

Denken Sie daran, das Sprichwort von Brian Kernighan:

  

Debugging ist doppelt so hart wie das Schreiben   der Code in dem ersten Platz.   Daher schreiben, wenn Sie den Code als   geschickt wie möglich, Sie sind durch   Definition, nicht intelligent genug, um zu debuggen   es.


Ich mache eine Menge Leistung entscheidend Codierung mit harter Echtzeit Fristen ... und ich habe noch nicht einen Ort, wo ein dichtes Einzeiler ist angemessen gesehen.

Ich habe auch bei der Zusammenstellung und Überprüfung der asm, um zu sehen, ob die Einzeiler hat eine bessere zusammengestellt asm Umsetzung aber noch nie gefunden, die Einzeiler zu sein lohnt sich.

messed um

Wie andere haben darauf hingewiesen, für

(int (*)(void*,void*))(numeric ? numcmp : strcmp)

dann folgt eine Typumwandlung

(int (*)(void*,void*))

und der Ausdruck

(numeric ? numcmp : strcmp)

C-Deklarationen können ziemlich schwierig sein zu lesen, aber es ist möglich zu lernen. Das Verfahren ist am inneren Teil zu starten und dann rechts einen Schritt gehen, dann links einen Schritt, rechts fort, links, rechts, links, usw. nach außen, bis beendet. Sie kreuzen nicht außerhalb einer Klammer vor allem innen ausgewertet wurde. Zum Beispiel für die obige Art gegossen, (*) zeigt dies ein Zeiger ist. Pointer war das einzige, was in der Klammer so dann wir auf der rechten Seite außerhalb bewerten. (void*,void*) zeigt an, dass ein Zeiger auf eine Funktion mit zwei Argumenten Zeiger ist. Schließlich gibt int den Rückgabetyp der Funktion. Die äußere Klammer macht dies eine Art Besetzung. Update: zwei ausführlichere Artikel: Die Rechts- / Spiral-Regel und Reading C Erklärungen:. Ein Leitfaden für die Mystified

Allerdings ist die gute Nachricht, dass, obwohl die oben äußerst nützlich zu wissen, gibt es eine extrem einfache Art und Weise zu betrügen : die cdecl Programm von C umwandeln kann Englische Beschreibung und vice versa:

cdecl> explain (int (*)(void*,void*))
cast unknown_name into pointer to function (pointer to void, pointer to void) returning int
cdecl> declare my_var as array 5 of pointer to int
int *my_var[5]
cdecl>

Übung: Welche Art von Variable i ist

int *(*(*i)[])(int *)

Antwort in rot13 , falls Sie nicht über cdecl auf Ihrem Rechner installiert (aber Sie sollte wirklich!):

pqrpy> rkcynva vag *(*(*v)[])(vag *)
qrpyner v nf cbvagre gb neenl bs cbvagre gb shapgvba (cbvagre gb vag) ergheavat cbvagre gb vag
pqrpy>

Ich würde wahrscheinlich es wie folgt lauten:

typedef int (*PFNCMP)(void *, void *);

PFNCMP comparison_function;

if (numeric)
{
    comparison_function =  numcmp;
}
else
{
    comparison_function = strcmp;
}

qsort((void**) lineptr, 0, nlines-1, comparison_function);

Das Beispiel in der Frage hat einen expliziten Fall.

Ihre Logik korrekt ist, denke ich. Es ist in der Tat zu „Zeiger auf Funktion, die zwei void-Zeiger und gibt einen int bekommt“ Casting, die die erforderliche Art der Methodensignatur ist.

Sowohl numcmp und strcmp sind Zeiger auf Funktionen, die zwei char* als Parameter übernehmen und gibt eine int. Die qsort Routine erwartet einen Zeiger auf eine Funktion, die zwei void* als Parameter nimmt und gibt eine int. Daraus ergibt sich die Besetzung. Dies ist sicher, da void* als generischer Zeiger wirkt. Nun zu der Erklärung zu lesen: Lassen Sie uns nehmen Ihre strcmp Erklärung:

 int strcmp(char *, char *);

Der Compiler liest es als strcmp ist eigentlich:

 int (strcmp)(char *, char *)

eine Funktion (abklingenden auf einen Zeiger auf eine Funktion, in den meisten Fällen), die zwei char * Argumente annimmt. Der Typ des Zeigers strcmp ist daher:

 int (*)(char *, char *)

Wenn also Sie brauchen eine andere Funktion zu werfen kompatibel sein, um strcmp Sie die oben genannten verwenden würden, wie die type zu gieße.

Da in ähnlicher Weise qsort die Komparator Argument nimmt zwei void *s und damit die ungeradee Form!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top