Perché le funzioni con valore assoluto in C non accettano input const?


23

In C, il prototipo per la funzione di valore assoluto (che accetta un float) è

 float fabsf( float );

Perché questo prototipo non accetta un valore costante, come questo:

 float fabsf( float const );

fabsf non cambierà il valore dell'input, vero?

Se ho una funzione che accetta un input e chiama fabsf, sono costretto a evitare di specificare l'input come const?

Qual è il modo appropriato per gestire la correttezza const in questa situazione?


26
constè ridondante qui, cosa stai succedendo?
MM

1
@MM Mi aspetto che creerebbe un errore in fase di compilazione se provassi a modificare il valore dell'input all'interno della funzione. È errato?
user24205

16
Poiché il parametro all'interno della funzione è una copia locale, l'aggiunta constè completamente priva di significato.
Lundin,

1
" fabsf non cambierà il valore dell'input, vero? " Come hai potuto dirlo? Il parametro viene passato per valore.
David Schwartz,

Il seguente codice è C legale: float const x = -1.0; float y = fabsf(x);così sembra a me che fabsf fa accettare input const. Non c'è modo di dire "puoi passarmi un floatvalore ma non puoi passare un const float". (E come vediamo nelle risposte, C non fornisce un modo per richiedere che l'ingresso in una funzione sia a float const.)
David K

Risposte:


14

modificare

Come ha commentato MM, sui parametri di prototipi del constviene ignorato. La fonte modificata della risposta originale (vedi sotto) mostra questo:

float correct(float const value);

float erroneous(float const value);

float changer(float value);

float correct(float value) {
  return -value;
}

float erroneous(float value) {
  value = -value;
  return value;
}

float changer(float value) {
    value = -value;
    return value;
}

Non c'è nessun messaggio di errore.

Ad ogni modo, lascerò l'originale sul posto nella speranza che possa essere d'aiuto.


Originale

Il constparametro at rende questo parametro di sola lettura all'interno della funzione.

Per esempio:

float correct(float const value) {
  return -value;
}

float erroneous(float const value) {
  value = -value;
  return value;
}

float changer(float value) {
  value = -value;
  return value;
}

Questa fonte non verrà compilata senza un messaggio di errore.

La funzione correct()leggerà il valore dato, cambierà il suo segno e restituirà il valore negato.

La funzione erroneous()sembra fare esattamente lo stesso, tranne per il fatto che è presente un'assegnazione al parametro. Ma poiché il parametro è constquesto non è permesso.

Successivamente, la funzione changer()funzionerà come entrambe prima, ma non fornisce errori.

Diamo un'occhiata al sito di chiamata:

float f = 3.14159;
float g = correct(f); // or erroneous(f) or changer(f)

La variabile ffornita come argomento verrà copiata nel parametro value. Non cambierà mai anche se changer()verrà chiamato.

Potresti considerare i parametri come una sorta di variabili locali. In realtà sono per lo più gestiti in questo modo nel codice macchina generato.


Quindi, perché vedi constqualche volta? Lo vedi se un puntatore è definito come parametro.

Quando non si desidera che il valore indicato venga modificato, è necessario aggiungere const; ma fallo nella posizione corretta!

void effective(int const * pointer);

void futile(int * const pointer);

void possible_but_overly_restricted(int const * const pointer);

La domanda riguarda i prototipi, tuttavia, il prototipo float fabsf( float const );non ha nulla a che fare con l'implementazione della funzione (che non deve ripetere il const), infatti constviene completamente ignorato nel prototipo
MM

2
Const può andare nelle definizioni delle funzioni senza andare nel prototipo?
user24205

3
@ user24205 sì, può
Daniel Jour,

33

C usa il passaggio per valore. Il valore per il parametro di una funzione è una copia dell'argomento fornito.

È OK copiare sia float const che non const e il risultato è un float non const.

È simile al compito:

const float f = 5.5f;
float g = f;   // OK

In effetti, il linguaggio specifica che il valore di un'espressione non può mai essere const, cioè quando un valore viene letto da una variabile, quel valore non è constnemmeno se fosse la variabile.


8

Poiché il linguaggio C utilizza la semantica pass by value, qualsiasi argomento che gli viene passato, sebbene possa essere modificato internamente, non influisce direttamente sul valore passato.

Ciò significa che dal punto di vista del chiamante, float fabsf( float );e float fabsf( const float );sono gli stessi. Quindi non ha senso fare il parametro const.

Dove si fa senso per l'uso constè se il parametro si passa è un puntatore, ad esempio:

void print_string(char *str)

Questa funzione, nonostante ciò che suggerisce il nome, può dereferenziare il puntatore dato e modificare ciò che punta, cioè str[0] = 'x', per provocare una modifica visualizzabile dalla funzione chiamante. Se questa funzione fosse definita in questo modo:

void print_string(const char *str)

Al chiamante viene garantito che la funzione non può eseguire alcuna modifica a ciò che strindica.


"Il chiamante ha la certezza che la funzione non può eseguire alcuna modifica ..." non è vero. La funzione conosce l'indirizzo dei dati e può quindi modificarlo, con, ad esempio: ((char*)str)[0] = 'f'. L' const ... *elenco degli argomenti è quindi solo una "dichiarazione di intenti".
Oromoiluig,

5

Per aggiungere una prospettiva di avvocato linguistico:

Affinché due tipi di funzioni siano compatibili, entrambi devono specificare i tipi di ritorno compatibili. Inoltre, gli elenchi dei tipi di parametri, se presenti, devono concordare nel numero di parametri e nell'uso del terminatore a puntini di sospensione; i parametri corrispondenti devono avere tipi compatibili . [..] Nella determinazione della compatibilità del tipo e di un tipo composito, [..] ogni parametro dichiarato con tipo qualificato è considerato avere la versione non qualificata del tipo dichiarato .

N1570 6.7.6.3/15

Ciò significa che questi due sono compatibili:

void foo(int const);
void foo(int);

Pertanto è possibile scrivere il prototipo con o senza const(il che significa senza più senso; meno scrivere / leggere) e aggiungere constla definizione della funzione se si desidera evitare di modificare accidentalmente il parametro (copiato - chiamare per valore!) All'interno delle funzioni corpo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.