Pourquoi les fonctions de valeur absolue en C n'acceptent-elles pas les entrées const?


23

En C, le prototype de la fonction de valeur absolue (qui accepte un flottant) est

 float fabsf( float );

Pourquoi ce prototype n'accepte-t-il pas une valeur constante, comme ceci:

 float fabsf( float const );

fabsf ne changera pas la valeur de l'entrée, n'est-ce pas?

Si j'ai une fonction qui accepte une entrée et appelle fabsf, suis-je obligé d'éviter de spécifier l'entrée comme const?

Quelle est la façon appropriée de gérer l'exactitude de const dans cette situation?


26
constest redondant ici, que pensez-vous qu'il se passe?
MM

1
@MM Je m'attends à ce que cela crée une erreur de temps de compilation si j'essayais de changer la valeur de l'entrée à l'intérieur de la fonction. Est-ce incorrect?
user24205

16
Étant donné que le paramètre à l'intérieur de la fonction est une copie locale, l'ajout constn'a aucun sens.
Lundin

1
" fabsf ne changera pas la valeur de l'entrée, n'est-ce pas? " Comment pouvez-vous le savoir? Le paramètre est transmis par valeur.
David Schwartz

Le code suivant est légal C: float const x = -1.0; float y = fabsf(x);il me semble que le fabsf fait d' accepter des entrées const. Il n'y a aucun moyen de dire "vous pouvez me passer une floatvaleur mais vous ne pouvez pas passer une const float." (Et comme nous le voyons dans les réponses, C ne fournit pas un moyen d' exiger que l'entrée d'une fonction soit a float const.)
David K

Réponses:


14

Éditer

Comme MM l'a commenté, sur les paramètres des prototypes, le constest ignoré. La source éditée de la réponse originale (voir ci-dessous) montre ceci:

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;
}

Il n'y a aucun message d'erreur.

Quoi qu'il en soit, je vais laisser l'original en place dans l'espoir que cela puisse aider.


Original

Le constparamètre at a rend ce paramètre en lecture seule à l'intérieur de la fonction.

Par exemple:

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

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

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

Cette source ne se compilera pas sans message d'erreur.

La fonction correct()lira la valeur donnée, changera son signe et renverra la valeur négative.

La fonction erroneous()semble faire la même chose, sauf qu'il y a une affectation au paramètre. Mais comme le paramètre est, constce n'est pas autorisé.

Ensuite, la fonction changer()fonctionnera comme les deux avant, mais elle ne donne aucune erreur.

Regardons le site de l'appel:

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

La variable fdonnée en argument sera copiée dans le paramètre value. Il ne changera jamais même s'il changer()sera appelé.

Vous voudrez peut-être regarder les paramètres comme une sorte de variables locales. En fait, ils sont principalement traités comme cela dans le code machine généré.


Alors, pourquoi voyez-vous constparfois? Vous le voyez si un pointeur est défini comme paramètre.

Lorsque vous ne voulez pas que la valeur pointée soit modifiée, vous devez ajouter const; mais faites-le à la bonne position!

void effective(int const * pointer);

void futile(int * const pointer);

void possible_but_overly_restricted(int const * const pointer);

La question concerne les prototypes cependant, le prototype float fabsf( float const );n'a rien à voir avec l'implémentation de la fonction (qui n'a pas à répéter le const), en fait, il constest ignoré entièrement dans le prototype
MM

2
Const peut-il entrer dans les définitions de fonction sans entrer dans le prototype?
user24205

3
@ user24205 oui c'est possible
Daniel Jour

33

C utilise le passage par valeur. La valeur du paramètre d'une fonction est une copie de l'argument que vous donnez.

Il est correct de copier les flotteurs const et non const, et le résultat est un flotteur non const.

C'est similaire à l'affectation:

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

En fait, le langage spécifie que la valeur d'une expression ne peut jamais être const, c'est-à-dire quand une valeur est lue dans une variable, cette valeur n'est pas constmême si la variable l'était.


8

Étant donné que le langage C utilise la sémantique de passage par valeur, tout argument que vous lui passez, bien qu'il puisse être modifié en interne, n'affecte pas directement la valeur que vous transmettez.

Cela signifie que du point de vue de l'appelant, float fabsf( float );et float fabsf( const float );sont les mêmes. Il est donc inutile de faire le paramètre const.

Il peut être judicieux d'utiliser constle paramètre si vous passez un pointeur, par exemple:

void print_string(char *str)

Cette fonction, malgré ce que son nom l'indique, peut déréférencer le pointeur donné et modifier ce qu'il pointe, c'est str[0] = 'x'-à- dire pour entraîner un changement visible par la fonction appelante. Si cette fonction était définie comme ceci:

void print_string(const char *str)

L'appelant est assuré que la fonction ne peut effectuer aucune modification sur ce qui strpointe vers.


"L'appelant est assuré que la fonction ne peut effectuer aucune modification ..." n'est pas vrai. La fonction connaît l'adresse des données et peut donc le modifier, avec, par exemple: ((char*)str)[0] = 'f'. La const ... *liste des arguments n'est donc qu'une "déclaration d'intention".
oromoiluig

5

Pour ajouter une perspective d'avocat linguistique:

Pour que deux types de fonctions soient compatibles, les deux doivent spécifier des types de retour compatibles. De plus, les listes de types de paramètres, si les deux sont présentes, doivent convenir du nombre de paramètres et de l'utilisation du terminateur de points de suspension; les paramètres correspondants doivent avoir des types compatibles . [..] Dans la détermination de la compatibilité de type et d'un type composite, [..] chaque paramètre déclaré avec un type qualifié est considéré comme ayant la version non qualifiée de son type déclaré .

N1570 6.7.6.3/15

Cela signifie que ces deux sont compatibles:

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

Par conséquent, vous pouvez écrire le prototype avec ou sans const(ce qui signifie sans plus de sens; moins à taper / lire) et pouvez ajouter constla définition de fonction si vous voulez éviter de modifier accidentellement le paramètre (copié - appeler par valeur!) À l'intérieur des fonctions corps.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.