2009-03-20 1 views
7

Eventuali duplicati:
Problem compiling K&R examplePointer avvertimento tipo non corrispondente nell'esempio da K & R C

Ultimamente ho lavorato la mia strada attraverso il linguaggio di programmazione C da K & R.

Nella sezione 5.11 sono riportati i puntatori alle funzioni e dopo aver digitato il loro esempio: un'implementazione quicksort in cui forniamo un puntatore al compari funzione figlio che vogliamo usare - Ricevo un avvertimento dal compilatore: mancata corrispondenza del tipo di puntatore nell'espressione condizionale. (Il mio compilatore è 4.0.1 gcc su OS X 10.5.6)

La linea dall'esempio che fa scattare l'avviso è:

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

Il programma esegue senza va in segfault, ma mi piace smoosh ogni avviso Posso, o almeno capire le loro cause.

La dichiarazione di funzione per numcmp assomiglia:

int numcmp(char *, char *); 

Ma secondo la pagina di manuale, stcmp ha questa firma:

int strcmp(const char *s1, const char *s2); 

è il monito semplice a causa delle leggermente diverse firme dei metodi? Quali sono le conseguenze dell'ignorare l'avvertimento?

+0

Eddie indicò un dupe. Ho votato per chiudere la mia domanda, ma ho pensato che ci sarebbe stato un modo in cui il proprietario poteva chiuderla sommariamente. – Dana

+0

Dana, check out [Esempio di compilazione di problemi K & R] (http://stackoverflow.com/questions/616906/problem-compiling-kr-example/616929) e probabilmente troverai la risposta alla tua domanda lì. Facci sapere se non lo fai. – Eddie

risposta

1

Un modo per provare e diagnosticare è vedere cosa succede se si sostituisce l'espressione con?: Con solo uno dei due.

Se succede solo per strcmp e non per numcmp, allora potrebbe essere a causa del const char *. Penso che mentre char * può sempre essere convertito in void *, non è possibile convertire const char * in void * come "safe".

Se è con entrambi, allora forse si tratta di qualche problema con i puntatori di funzione, dove il char * convertito in void * funziona, ma le firme devono essere identiche e avere vuoti invece di caratteri sono un problema.

3

Risposta breve: K & R non sapeva C.

Risposta lunga: Sono stati ostacolati dal fatto che quando hanno iniziato, nessuno sapeva C, quindi erano sorta di che lo compongono come loro andarono insieme.

(leggermente) forma meno frivolo della lunga risposta: Il linguaggio si è evoluto (alcuni direbbero cambiato) un bel po 'dal momento che K & R è stato scritto, ma se non hai la versione e-book con l'esempio dinamica morphing, gli esempi nella tua copia di K & R non hanno tenuto il passo con il linguaggio "nuovo e approvato" ("ora con ancora più ANSI!").

7

Sebbene sia possibile eseguire il cast implicito di un char * in un void *, non è possibile fare lo stesso per un puntatore a funzione con questi tipi (senza un avviso). Il compilatore è più attento con la corrispondenza dei tipi sulle firme delle funzioni.

Senza contare che ciò che accade all'interno di qsort sarebbe il contrario: cioè, un void * verrebbe castato in un char * in numcmp e const char * in strcmp.

E il compilatore dovrebbe emettere un avviso in questi casi. Se devi davvero usare una funzione che non ha gli stessi tipi dei parametri, forse dovresti usare una funzione wrapper che corrisponda ai tipi, e poi esegue il cast esplicito appropriato quando chiama la funzione originale.

Per esempio:

static int strcmp_wrapper(void* s1, void* s2) { 
    return strcmp((char*)s1, (char*)s2); 
} 

static int numcmp_wrapper(void* n1, void* n2) { 
    return numcmp((char*)n1, (char*)n2); 
} 

qsort((void **) lineptr, 0, nlines-1, 
     (numeric ? numcmp_wrapper : strcmp_wrapper)); 

E la firma moderna per qsort è

void 
qsort(void *base, size_t nel, size_t width, 
     int (*compar)(const void *, const void *)); 

La questione della const non sembra entrare in gioco nella tua domanda, ma K & R non ha fatto avere const.

+0

Un'altra opzione è quella di cambiare l'espressione ternaria al seguente: numerico? (int (*) (void *, void *)) numcmp: (int (*) (void *, void *)) strcmp); Così semplicemente passando le due diverse funzioni separatamente a qsort. Questo eviterà anche qualsiasi avvertimento dato dal compilatore – bryanph