Warum akzeptieren die Absolutwertfunktionen in C keine konstanten Eingaben?

23

In C ist der Prototyp für die Absolutwertfunktion (die einen Float akzeptiert)

 float fabsf( float );

Warum akzeptiert dieser Prototyp keinen konstanten Wert wie diesen:

 float fabsf( float const );

fabsf wird den Wert der Eingabe nicht ändern, oder?

Wenn ich eine Funktion habe, die eine Eingabe akzeptiert und fabsf aufruft, muss ich dann vermeiden, die Eingabe als const anzugeben?

Was ist der geeignete Weg, um in dieser Situation mit konstanter Korrektheit umzugehen?

user24205
quelle
26
constist hier überflüssig, was denkst du passiert?
MM
1
@MM Ich gehe davon aus, dass es zu einem Fehler bei der Kompilierung kommen würde, wenn ich versuchen würde, den Wert der Eingabe innerhalb der Funktion zu ändern. Ist das falsch
user24205
16
Da der Parameter in der Funktion eine lokale Kopie ist, ist das Hinzufügen constvöllig bedeutungslos.
Lundin
1
" fabsf wird den Wert der Eingabe nicht ändern, oder? " Wie können Sie das beurteilen? Der Parameter wird als Wert übergeben.
David Schwartz
Der folgende Code ist legal C: float const x = -1.0; float y = fabsf(x);so scheint es mir , dass fabsf tut const - Eingänge. Es gibt keine Möglichkeit zu sagen: "Sie können mir einen floatWert übergeben, aber Sie können einen nicht übergeben const float." (Und wie wir in den Antworten sehen, bietet C keine Möglichkeit, zu verlangen, dass die Eingabe für eine Funktion a ist float const.)
David K

Antworten:

14

Bearbeiten

Wie MM kommentierte, wird bei Parametern in Prototypen das constignoriert. Die bearbeitete Quelle der ursprünglichen Antwort (siehe unten) zeigt Folgendes:

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

Es gibt keine Fehlermeldung.

Wie auch immer, ich werde das Original an Ort und Stelle lassen, in der Hoffnung, dass es helfen könnte.


Original

Der constParameter at a macht diesen Parameter innerhalb der Funktion schreibgeschützt.

Zum Beispiel:

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

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

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

Diese Quelle wird nicht ohne Fehlermeldung kompiliert.

Die Funktion correct()liest den angegebenen Wert, ändert sein Vorzeichen und gibt den negierten Wert zurück.

Die Funktion erroneous()scheint effektiv dasselbe zu tun, außer dass dem Parameter eine Zuordnung vorliegt. Da der Parameter jedoch ist, ist constdies nicht zulässig.

Als nächstes funktioniert die Funktion changer()wie beide zuvor, gibt jedoch keine Fehler aus.

Schauen wir uns die Anrufseite an:

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

Die fals Argument angegebene Variable wird in den Parameter kopiertvalue . Es wird sich nie ändern, auch wenn changer()es aufgerufen wird.

Möglicherweise möchten Sie Parameter als eine Art lokale Variablen betrachten. Tatsächlich werden sie im generierten Maschinencode meistens so behandelt.


Also, warum siehst du constmanchmal? Sie sehen es, wenn ein Zeiger als Parameter definiert ist.

Wenn Sie nicht möchten, dass der Wert , auf den gezeigt wird, geändert wird, müssen Sie hinzufügen const. aber mach es an der richtigen Position!

void effective(int const * pointer);

void futile(int * const pointer);

void possible_but_overly_restricted(int const * const pointer);
der Busybee
quelle
Die Frage float fabsf( float const );bezieht sich jedoch auf Prototypen, der Prototyp hat nichts mit der Funktionsimplementierung zu tun (die das nicht wiederholen muss const), tatsächlich constwird die im Prototyp vollständig ignoriert
MM
2
Kann const in Funktionsdefinitionen gehen, ohne in den Prototyp zu gehen?
user24205
3
@ user24205 ja es kann
Daniel Jour
33

C verwendet den Pass-by-Wert. Der Wert für den Parameter einer Funktion ist eine Kopie des von Ihnen angegebenen Arguments.

Es ist in Ordnung, sowohl const- als auch non-const-Floats zu kopieren, und das Ergebnis ist ein non-const-Float.

Es ist ähnlich wie bei der Zuordnung:

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

Tatsächlich gibt die Sprache an, dass der Wert eines Ausdrucks niemals sein kann const, dh wenn ein Wert aus einer Variablen gelesen wird, ist dieser Wert nicht consteinmal, wenn die Variable war.

MM
quelle
8

Da die C-Sprache die Semantik für die Übergabe von Werten verwendet , wirkt sich jedes Argument, das Sie an sie übergeben, nicht direkt auf den Wert aus, den Sie übergeben, obwohl es intern geändert werden könnte.

Dies bedeutet, dass aus Sicht des Anrufers float fabsf( float );und float fabsf( const float );sind die gleichen. Es macht also keinen Sinn, den Parameter zu machen const.

Wo es tut sinnvoll zu verwenden constist , wenn der Parameter Sie in geben einen Zeiger ist, zum Beispiel:

void print_string(char *str)

Diese Funktion kann trotz des Namens den angegebenen Zeiger dereferenzieren und ändern, was er zeigt, dh str[0] = 'x'zu einer Änderung führen, die von der aufrufenden Funktion angezeigt werden kann. Wenn diese Funktion folgendermaßen definiert wäre:

void print_string(const char *str)

Dem Aufrufer wird sichergestellt, dass die Funktion keine Änderungen an den strPunkten vornehmen kann, auf die verwiesen wird .

dbush
quelle
"Der Anrufer ist sichergestellt, dass die Funktion keine Änderungen vornehmen kann ..." ist nicht wahr. Die Funktion kennt die Adresse der Daten und kann diese daher ändern, z ((char*)str)[0] = 'f'. B.: . Die const ... *in der Argumentliste enthaltene ist daher nur eine "Absichtserklärung".
Oromoiluig
5

So fügen Sie eine Perspektive für einen Sprachanwalt hinzu:

Damit zwei Funktionstypen kompatibel sind, müssen beide kompatible Rückgabetypen angeben. Darüber hinaus müssen die Parametertyplisten, sofern beide vorhanden sind, in der Anzahl der Parameter und in der Verwendung des Ellipsen-Terminators übereinstimmen. entsprechende Parameter müssen kompatible Typen haben . [..] Bei der Bestimmung der Typkompatibilität und eines zusammengesetzten Typs [..] wird angenommen, dass jeder mit qualifiziertem Typ deklarierte Parameter die nicht qualifizierte Version seines deklarierten Typs aufweist .

N1570 6.7.6.3/15

Das heißt, diese beiden sind kompatibel:

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

Daher können Sie den Prototyp mit oder ohne schreiben const (was bedeutet, dass ohne sinnvoller ist; weniger zu tippen / lesen) und constdie Funktionsdefinition hinzufügen, wenn Sie vermeiden möchten, dass der Parameter (kopiert - Aufruf nach Wert!) In den Funktionen versehentlich geändert wird Körper.

Daniel Jour
quelle