2014-06-12 17 views
5

Ho una semplice domanda su GLib.Perché GLib non usa 'const' in queste funzioni?

Ho il codice seguente:

static const char *words[] = { "one", "two", "three", NULL }; 

void main() { 
    puts(g_strjoinv("+", words)); 
} 

Questo codice stampe one+two+three. Usa una funzione GLib che unisce le stringhe.

La signature di tale funzione è:

char *g_strjoinv (const char *separator, char **str_array); 

(. Per essere esatti, GLib utilizza gchar, non char, ma cerchiamo di ignorare questa)

Ora, mi chiedo perché il parametro è char **str_array e non const char **str_array. Mi costringe a fare un cast esplicito per sbarazzarsi di avvertimento del compilatore ("previsto 'char **', ma l'argomento è di tipo 'char **'"):

puts(g_strjoinv("+", (char **)words)); 

mi guardo e mi GLib's reference vedere che tutte le le funzioni sono definite in questo modo: accettano char **, non const char **.

Perché è quello? Perché GLib non usa const char **?

La necessità di utilizzare un cast esplicito per sbarazzarsi di const rende il mio codice meno sicuro (perché il compilatore non controlla più la compatibilità degli argomenti). Inoltre mi rende nervoso perché GLib non "firma un contratto" che dice che non cambierà i miei dati.

+1

Grande domanda, str_array sicuramente non viene modificato (?), In tal caso const avrebbe senso. – this

+0

@ self: Sì, e non è un problema con solo questa funzione. È in * all * delle funzioni di GLib che accetta una serie di stringhe. Immagino che abbiano una buona ragione per farlo e voglio sapere di cosa si tratta. –

+3

Si consiglia di guardare [questa domanda] (http://c-faq.com/ansi/constmismatch.html). Se tu avessi un normale 'char **' che è del tutto possibile, non saresti in grado di passarlo ad una funzione aspettando 'const char **' senza cast, quindi non risolverai un problema con dichiarandolo come tale. –

risposta

6

L'assunzione in tua domanda è che se il secondo argomento di g_strjoinv() è stata dichiarata come tipo const char **, allora si può anche facilmente passare sia un const char ** o un char ** ad esso.

Sfortunatamente, questo non è vero. Come spiegato in this question from the comp.lang.c FAQ, utilizzando un puntatore a T (per qualsiasi tipo T) in cui è previsto un puntatore a const T OK, ma solo dove la mancata corrispondenza si trova al livello più elevato di riferimento indiretto. Vale a dire, è possibile passare un previsto, ma non è possibile (senza un cast) passare un char ** in cui è previsto un const char **, perché in questo caso la mancata corrispondenza è al secondo livello di riferimento indiretto. La domanda collegata spiega in dettaglio perché funziona in questo modo, che è "un po 'oscuro".

Così il risultato è non v'è nessun tipo (in C) che accettare sia un char ** e const char ** senza almeno uno di essi richiede un cast. Stando così le cose, probabilmente non c'è molto motivo per preferire l'altro o la convenienza, e gli autori della biblioteca apparentemente hanno deciso di andare con il primo. Per pura speculazione, immagino che voler passare uno char ** sia leggermente più comune di quello di voler passare un const char **, e quindi l'opzione che hanno scelto è probabilmente più conveniente.

Nel tuo caso, puoi semplicemente eliminare il qualificatore const dalla definizione dell'array.Potrebbe sembrare una cattiva forma, se ti piace const, ma dal momento che hai una serie di puntatori che puntano a stringhe letterali, il tuo programma è schiacciante probabilità di lamentarsi a voce alta e fallire se qualcosa tenta di scrivere comunque, quindi non sei davvero perdere la sicurezza in ogni modo significativo in questo caso particolare. Anche se è un comportamento indefinito tentare di modificarli, i valori letterali stringa hanno tipo array di char in C, non array di const char (a differenza di C++).

Un po 'più oscuro, ma anche se si poteva passare come un const char **, la funzione qui potrebbe ancora modificare i puntatori anche se non potrebbe modificare ciò a cui puntano, e giusta causa caos in un modo diverso, in modo che il promettere che la funzione eseguita non garantirebbe comunque che ciò che si passa alla funzione non venga modificato in alcun modo.

+0

Questa è una ** risposta ** eccellente, grazie mille! Avevo già riscontrato questo problema ma non sapevo che fosse collegato a questo caso presente. Ora, grazie a te, lo capisco pienamente. A proposito, tu dici che posso semplicemente rilasciare il mio "const", ma quando faccio questo GCC mi avverte ("inizializzazione scarta const '..."), perché, immagino, si vedono stringhe letterali come costanti. –

+0

(BTW, grazie anche per l'ultimo paragrafo. Le mie capacità C sono un po 'arrugginite e avevo bisogno di questa correzione.) –

+0

Sembra un avvertimento spurio, sei sicuro di non compilarlo come C++, o con qualche set di estensioni ? La compilazione come standard C non dovrebbe darti questo avvertimento. –

Problemi correlati