Domanda

Il nostro strumento di analisi statica si lamenta "un qualificatore di tipo inutile su tipo di ritorno" quando abbiamo prototipi in file di intestazione come ad esempio:

const int foo();

Abbiamo definito in questo modo perché la funzione restituisce una costante che non cambierà mai, pensando che l'API sembrava più chiara con const a posto.

Mi sento come se questo è simile a in fase di inizializzazione in modo esplicito le variabili globali a zero per chiarezza, anche se lo standard C si afferma già che tutte le variabili globali vengono inizializzati a zero se non esplicitamente inizializzato. Alla fine della giornata, in realtà non importa. (Ma lo strumento di analisi statica non si lamenta di questo.)

La mia domanda è, c'è qualche ragione per cui questo potrebbe causare un problema? Dovremmo ignorare gli errori generati dallo strumento, o dobbiamo placare l'utensile al possibile costo di un'API meno chiara e coerente? (Si restituisce altre costanti const char* che lo strumento non ha un problema con.)

È stato utile?

Soluzione

Di solito è meglio per il vostro codice per descrivere il più accuratamente possibile quello che sta succedendo. Stai ricevendo questo avviso perché il const in const int foo(); è sostanzialmente priva di significato. L'API sembra solo più chiaro se non si sa che cosa significa la parola chiave const. Non sovraccaricare il che significa così; static è già abbastanza grave così com'è, e non c'è motivo di aggiungere il potenziale per più confusione.

const char * significa qualcosa di diverso rispetto const int fa, che è il motivo per cui il vostro strumento non si lamenta a questo proposito. Il primo è un puntatore a una stringa costante, significa qualsiasi codice chiamando la funzione che restituisce questo tipo non dovrebbe tentare di modificare il contenuto della stringa (che potrebbe essere nella ROM per esempio). In quest'ultimo caso, il sistema non ha modo di far rispettare che non apportano modifiche al int restituito, in modo che la qualificazione è priva di significato. Una più stretta parallelamente ai tipi di ritorno potrebbe essere:

const int foo();
char * const foo2();

che sia sì che il vostro analisi statica per dare l'avvertimento - l'aggiunta di un qualificatore const ad un valore di ritorno è un'operazione senza senso. Ha senso solo quando si ha un parametro di riferimento (o tipo di ritorno), come il vostro esempio const char *.

In realtà, ho solo fatto un piccolo programma di test, e GCC avverte anche in modo esplicito su questo problema:

test.c:6: warning: type qualifiers ignored on function return type

Quindi non è solo il vostro programma di analisi statica che si lamenta.

Altri suggerimenti

È possibile utilizzare una tecnica diversa per illustrare il vostro intento senza fare gli strumenti infelice.

#define CONST_RETURN

CONST_RETURN int foo();

Non hai un problema con const char * perché è dichiarare un puntatore a caratteri costanti, non un puntatore costante.

Ignorando il const per ora, foo() restituisce un valore. Si può fare

int x = foo();

e assegnare il valore restituito dal foo() al x variabili, più o meno allo stesso modo si può fare

int x = 42;

per assegnare il valore 42 alla variabile x.
Ma non si può cambiare il 42 ... o il valore restituito da foo(). Dire che il valore restituito da foo() non può essere modificato, applicando la parola chiave const al tipo di foo() compie nulla.

Valori non possono essere const ( o restrict, o volatile ). Solo gli oggetti possono avere tipo di qualificazione.


Contrasto con

const char *foo();

In questo caso, foo() restituisce un puntatore ad un oggetto. L'oggetto puntato dal valore restituito può essere const qualificato.

L'int viene restituito da copia . Può essere una copia di un const, ma quando si è assegnato a qualcosa d'altro, qualcosa che in virtù del fatto che era assegnabile, non può per definizione essere un const.

Il const parola chiave ha una semantica specifici all'interno della lingua, mentre qui si sta abusando come essenzialmente un commento. Invece di aggiungere chiarezza, suggerisce piuttosto un malinteso della semantica della lingua.

const int foo() è molto diverso da const char* foo(). const char* foo() restituisce un array (solitamente una stringa) il cui contenuto non è consentito cambiare. Pensate alla differenza tra:

 const char* a = "Hello World";

e

const int b = 1;

a è ancora una variabile e può essere assegnato a altre stringhe che non posso cambiare, mentre non b è una variabile. Quindi

const char* foo();
const char* a = "Hello World\n";
a = foo();

è consentito, ma

const int bar();
const int b = 0;
b = bar();

Non è consentito, anche con la dichiarazione di const bar().

Sì. Vorrei consigliare la scrittura di codice "in modo esplicito", perché rende chiaro a chiunque (compreso te) durante la lettura del codice di quello che volevi dire. Si sta scrivendo codice per altri programmatori a leggere , non per compiacere i capricci degli strumenti di compilazione e di analisi statica!

(Tuttavia, non bisogna stare attenti che ogni "codice non necessario" come non provoca codice diverso da generare!)

Alcuni esempi di codifica esplicita migliorando la leggibilità / manutenzione:

  • Ho posto parentesi intorno porzioni di espressioni aritmetiche per specificare in modo esplicito quello che voglio che accada. Ciò rende chiaro a qualsiasi lettore quello che volevo dire, e salva me doversi preoccupare di (o fare ay errori con) regole di precedenza:

    int a = b + c * d / e + f;      // Hard to read- need to know precedence
    int a = b + ((c * d) / e) + f;  // Easy to read- clear explicit calculations
    

  • In C ++, se si ignora una funzione virtuale, quindi nella classe derivata è possibile dichiararla senza menzionare "virtuale" a tutti. Chiunque legga il codice non può dire che si tratta di una funzione virtuale, che può essere disastrosamente fuorviante! Tuttavia si può tranquillamente utilizzare la parola chiave virtuale:

    virtual int MyFunc()
    e questo lo rende chiaro a chiunque legga l'intestazione di classe che questo metodo è virtuale. (Questo "C ++ sintassi bug" è fissato in C # richiedendo l'utilizzo della parola chiave "override" in questo caso - prova in più, se qualcuno aveva bisogno di esso che manca il "superfluo virtuale" è una pessima idea)

Si tratta di due chiari esempi in cui il codice aggiungendo "non necessario" renderà il codice più leggibile e meno incline a bug.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top