Wann und für welche Zwecke sollte das Schlüsselwort const in C für Variablen verwendet werden?

58

Während ich meinen Code hier überprüfen ließ, tauchte das Problem der Verwendung des constSchlüsselworts auf. Ich verstehe, dass es zum Implementieren von Nur-Lese-Verhalten für Variablen verwendet wird.

Ich bin verwirrt über die verschiedenen Situationen, in denen es nützlich sein kann.

  • Sollte es aus Gründen der Klarheit in Funktionsprototypen verwendet werden?
  • Sollte es als Sicherheitsmaßnahme während der Codeentwicklung verwendet werden?
  • Soll es im Rahmen verschiedener Funktionen zur Deklaration von Laufzeitkonstanten verwendet werden?
  • Sollte es überhaupt verwendet werden?

Diese Frage ist nur ein Beispiel für die Verwirrung, mit der ich konfrontiert bin. Die allgemeine Verwirrung ist

  • Wann sollte das constSchlüsselwort in der C-Programmierung verwendet werden?
  • Welche verschiedenen Arten von Vorteilen können mit diesem Schlüsselwort in C erzielt werden?
  • Gibt es irgendwelche Nachteile der Verwendung von constSchlüsselwörtern?


Es wurde darauf hingewiesen, dass diese Frage aufgrund all dieser Fragen im Detail meiner Frage zu weit gefasst sein kann. Ich wollte nur klarstellen, dass diese Fragen nur die Verwirrung in Bezug auf die Hauptfrage klären sollen.

Wann und für welche Zwecke sollte das Schlüsselwort const in C für Variablen verwendet werden?

Es kann auch umformuliert werden als

Die richtige Verwendung von constSchlüsselwörtern in C` mit den Vor- und Nachteilen derselben.

Aseem Bansal
quelle
Damit die Abstimmung geschlossen bleibt, erläutern Sie bitte, warum sie nicht in die Kategorie von fällt Specific issues with software development. Ich bin ziemlich spezifisch.
Aseem Bansal
Ich vermute, es liegt daran, dass Sie in einem Beitrag mehrere Fragen gestellt haben und Ihre Frage daher in die Kategorie "Zu breit "
Robert Harvey
1
@RobertHarvey Alle diese Fragen sollen nur meine Verwirrung erklären. Meine einzige Frage bleibt der Titel dieser Frage. Eine gute Antwort darauf würde alle diese verwandten Fragen abdecken. So bleibt es ein specific issue. Die richtige Verwendung von constSchlüsselwörtern in C` mit den Vor- und Nachteilen derselben.
Aseem Bansal
@RobertHarvey Ist es jetzt besser?
Aseem Bansal

Antworten:

64

Beim Überprüfen des Codes wende ich die folgenden Regeln an:

  • Verwenden Sie immer constfür Funktionsparameter, die als Referenz übergeben werden, wenn die Funktion die Daten, auf die verwiesen wird, nicht ändert (oder freigibt).

    int find(const int *data, size_t size, int value);
  • Verwenden Sie immer constfür Konstanten, die andernfalls mit einem #define oder einer Enumeration definiert werden könnten. Dadurch kann der Compiler die Daten im Nur-Lese-Speicher (ROM) lokalisieren (obwohl der Linker in eingebetteten Systemen häufig ein besseres Werkzeug für diesen Zweck ist).

    const double PI = 3.14;
  • Nie const in einer Funktion verwenden Prototyp für einen Parameter von übergeben Wert . Es hat keine Bedeutung und ist daher nur "Lärm".

    // don't add const to 'value' or 'size'
    int find(const int *data, size_t size, const int value); 
  • Verwenden Sie sie gegebenenfalls const volatilean Orten, die vom Programm nicht geändert werden können, sich aber möglicherweise noch ändern. Hardware-Register sind hier der typische Anwendungsfall, zum Beispiel ein Statusregister, das einen Gerätezustand widerspiegelt:

    const volatile int32_t *DEVICE_STATUS =  (int32_t*) 0x100;

Andere Verwendungen sind optional. Zum Beispiel können die Parameter an eine Funktion in der Funktion Implementierung kann als const gekennzeichnet werden.

// 'value' and 'size can be marked as const here
int find(const int *data, const size_t size, const int value)  
{
     ... etc

oder Funktion Rückgabewerte oder Berechnungen, die erhalten werden und sich dann nie ändern:

char *repeat_str(const char *str, size_t n) 
{
    const size_t len = strlen(str);
    const size_t buf_size = 1 + (len * n);
    char *buf = malloc(buf_size);
    ...

Diese Verwendungen von constweisen lediglich darauf hin, dass Sie die Variable nicht ändern werden. Sie ändern nicht, wie oder wo die Variable gespeichert wird. Der Compiler kann natürlich feststellen, dass eine Variable nicht geändert wird, aber indem constSie sie hinzufügen, können Sie dies erzwingen. Dies kann dem Leser helfen und zusätzliche Sicherheit bieten (obwohl Sie möglicherweise andere Probleme haben, wenn Ihre Funktionen so umfangreich oder kompliziert sind, dass dies einen großen Unterschied ausmacht). Bearbeiten - zB. Eine dicht codierte 200-Zeilen-Funktion mit verschachtelten Schleifen und vielen langen oder ähnlichen Variablennamen, die weiß, dass sich bestimmte Variablen niemals ändern, kann das Verständnis erheblich erleichtern. Solche Funktionen wurden schlecht entworfen oder gewartet.


Probleme mit const. Sie werden wahrscheinlich den Begriff "const Vergiftung" hören. Dies tritt auf, wenn das Hinzufügen constzu einem Funktionsparameter die Ausbreitung von 'constness' verursacht.

Edit - const Vergiftung: zum Beispiel in der Funktion:

int function_a(char * str, int n)
{
    ...
    function_b(str);
    ...
}

wenn wir ändern strzu constmüssen wir dann dafür sorgen , dass fuction_bauch ein nimmt const. Und so weiter , wenn function_bpassiert das strauf function_cusw. Wie man sich vorstellen kann dies schmerzhaft sein könnte , wenn es viele einzelne Dateien / Module breitet sich in. Wenn es sich in eine Funktion ausbreitet, die nicht geändert werden kann (z. B. eine Systembibliothek), ist eine Umwandlung erforderlich. Wenn Sie also constin vorhandenem Code herumstreuen, müssen Sie vielleicht Ärger machen. In neuem Code ist es jedoch am besten, constbei Bedarf eine konsistente Qualifizierung vorzunehmen .

Das heimtückischere Problem constist, dass es nicht in der Originalsprache war. Als Add-On passt es nicht ganz. Erstens hat es zwei Bedeutungen (wie in den obigen Regeln, was bedeutet "Ich werde das nicht ändern" und "Das kann nicht geändert werden"). Aber darüber hinaus kann es gefährlich sein. Kompilieren Sie diesen Code und führen Sie ihn aus. Je nach Compiler / Optionen kann er bei der Ausführung abstürzen:

const char str[] = "hello world\n";
char *s = strchr(str, '\n');
*s = '\0';

strchrgibt a char*nicht a zurück const char*. Wie der Aufrufparameter ist constmuss sie werfen den Aufrufparameter an char*. In diesem Fall wird die eigentliche schreibgeschützte Speichereigenschaft verworfen. Bearbeiten: - Dies gilt im Allgemeinen für Variablen im Nur-Lese-Speicher. Mit "ROM" meine ich nicht nur das physische ROM, sondern jeden Speicher, der schreibgeschützt ist, wie es bei den Code-Abschnitten von Programmen unter einem typischen Betriebssystem der Fall ist.

Viele Standard-Bibliotheksfunktionen verhalten sich genauso, seien Sie also vorsichtig : Wenn Sie echte Konstanten haben (dh im ROM gespeichert sind), müssen Sie sehr vorsichtig sein, um ihre Konstanz nicht zu verlieren.

William Morris
quelle
Es hat nicht wirklich zwei Bedeutungen. Es bedeutet nur, wie Sie sagen: " Ich werde das nicht ändern." Zum Beispiel ist es vollkommen gültig, eine const volatileVariable zu haben .
Detly
2
Dies gilt für Funktionsparameter, aber für Konstanten im Dateibereich ist beispielsweise eine constVariable schreibgeschützt: const"Dies kann nicht geändert werden". A const volatilehingegen sagt "Dies kann nicht geändert werden, aber es kann sich ändern". Ich werde meiner Antwort eine Erwähnung der Flüchtigen hinzufügen.
William Morris
Ich bin mit Ihrem Kommentar nicht einverstanden, nur mit der Idee, dass es eine Anweisung für den Compiler ist, ihn in das ROM zu stellen. Dies impliziert eine Art Laufzeitschutz gegen undefiniertes Verhalten (dh das Ändern einer Konstante durch irgendwie), was zu Missverständnissen wie "Warum kann ich diese constVariable durch einen Nicht- constZeiger ändern " führen kann (eine häufige Frage zu SO und jedem anderen C-Forum) !). Insgesamt mag ich diese Antwort aber :)
Detly
Sie haben Recht, "Put this in ROM" ist ungenau (obwohl prägnant :-) - Ich werde es in "Dies kann nicht geändert werden" ändern, was genauer ist. Danke für deine Kommentare.
William Morris
Dies ist eine großartige Übersicht. Ich möchte sagen, dass constsowohl schreibgeschützte Daten als auch schreibgeschützte Ansichten von Daten deklariert werden .
Jon Purdy
8

Generell wird in jeder Programmiersprache empfohlen, constden entsprechenden Modifikator zu verwenden

  • Dies kann dem Anrufer klar machen, dass sich das, was er übergeben hat, nicht ändern wird
  • Mögliche Geschwindigkeitsverbesserungen, da der Compiler sicher weiß, dass er bestimmte Dinge auslassen kann, die nur relevant sind, wenn sich der Parameter ändern kann
  • Schutz vor versehentlicher Wertänderung
TheLQ
quelle
1

Ja, das ist im Grunde die Antwort von TheLQ.

Ist eine Sicherheitsmaßnahme für den Programmierer, damit Sie eine Variable nicht ändern und keine Funktionen aufrufen, die sie möglicherweise ändern. In einem Array oder einer Struktur gibt der const-Bezeichner an, dass die Werte ihres Inhalts nicht geändert werden, und selbst der Compiler lässt dies nicht zu. Sie können den Wert der Variablen jedoch immer noch leicht mit nur einer Umwandlung ändern.

In dem, was ich normalerweise sehe, wird es hauptsächlich verwendet, um konstante Werte in Code einzufügen und um anzuzeigen, dass das Array oder die Struktur nicht geändert wird, wenn Sie eine bestimmte Funktion aufrufen. Dieser letzte Teil ist wichtig, da Sie beim Aufrufen einer Funktion, die Ihr Array oder Ihre Struktur ändert, möglicherweise die Originalversion beibehalten möchten, also eine Kopie der Variablen erstellen und diese dann an function übergeben. Wenn dies nicht der Fall ist, benötigen Sie die Kopie natürlich nicht, damit Sie zum Beispiel ändern können,

int foo(Structure s);

zu

int foo(const Structure * s);

und nicht die Kopie Overhead bekommen.

Beachten Sie zum Hinzufügen, dass C bestimmte Regeln für den const-Bezeichner hat. Zum Beispiel,

int b = 1;
const int * a = &b;

ist nicht dasselbe wie

int b = 1;
int * const a = &b;

Mit dem ersten Code können Sie a nicht ändern. Im zweiten Fall ist der Zeiger konstant, sein Inhalt jedoch nicht. Der Compiler ermöglicht es Ihnen, * a = 3;ohne einen Compilerfehler zu sagen , aber Sie können nicht aauf eine andere Sache verweisen.

lgarcia
quelle
0

In Übereinstimmung mit den Aussagen von TheLQ:

Wenn Sie mit einem Team von Programmierern zusammenarbeiten, constist die Deklaration eine gute Möglichkeit, um anzuzeigen, dass die Variable nicht geändert werden sollte, oder nur, um sich an große Projekte zu erinnern. In diesem Sinne ist es nützlich und kann viele Kopfschmerzen ersparen.

David Otano
quelle