it-swarm.com.de

Wann und zu welchen Zwecken sollte das Schlüsselwort const in C für Variablen verwendet werden?

Beim Abrufen von mein Code wurde hier überprüft trat das Problem der Verwendung des Schlüsselworts const auf. Ich verstehe, dass es zum Implementieren des schreibgeschützten Verhaltens von 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 bei der Codeentwicklung verwendet werden?
  • Sollte es im Rahmen verschiedener Funktionen zum Deklarieren 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 Schlüsselwort const in der C-Programmierung verwendet werden?
  • Welche verschiedenen Arten von Vorteilen können mit diesem Schlüsselwort in C erzielt werden?
  • Gibt es Nachteile bei der Verwendung des Schlüsselworts const?

Wann und zu welchen Zwecken sollte das Schlüsselwort const in C für Variablen verwendet werden?

Es kann auch umformuliert werden als

Die richtige Verwendung des Schlüsselworts const in C` mit den Vor- und Nachteilen desselben.

65
Aseem Bansal

Beim Überprüfen von Code wende ich die folgenden Regeln an:

  • Verwenden Sie const immer fü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 const immer für Konstanten, die andernfalls mit #define oder enum definiert werden könnten. Der Compiler kann die Daten als Ergebnis 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;
    
  • Verwenden Sie niemals const in einer Funktion Prototyp für einen Parameter, der von Wert übergeben wird. 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 gegebenenfalls const volatile An Orten, die vom Programm nicht geändert werden können, sich aber möglicherweise noch ändern. Hardwareregister sind hier der typische Anwendungsfall, beispielsweise ein Statusregister, das einen Gerätestatus widerspiegelt:

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

Andere Verwendungen sind optional. Beispielsweise können die Parameter einer Funktion innerhalb der Funktion Implementierung als const markiert werden.

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

oder Funktionsrü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 const zeigen nur an, dass Sie die Variable nicht ändern werden. Sie ändern nicht, wie oder wo die Variable gespeichert ist. Der Compiler kann natürlich herausfinden, dass eine Variable nicht geändert wird, aber durch Hinzufügen von const können Sie dies erzwingen. Dies kann dem Leser helfen und etwas Sicherheit bieten (obwohl Sie möglicherweise andere Probleme haben, wenn Ihre Funktionen groß oder kompliziert genug sind, dass dies einen großen Unterschied macht). Bearbeiten - zB. Eine dicht codierte Funktion mit 200 Zeilen, verschachtelten Schleifen und vielen langen oder ähnlichen Variablennamen, in dem Wissen, 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 "konstante Vergiftung" hören. Dies tritt auf, wenn das Hinzufügen von const zu einem Funktionsparameter dazu führt, dass sich 'constness' ausbreitet.

Edit - const Vergiftung: zum Beispiel in der Funktion:

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

Wenn wir str in const ändern, müssen wir sicherstellen, dass fuction_b auch ein const nimmt. Und so weiter, wenn function_b Das str an function_c Weitergibt. Wie Sie sich vorstellen können, kann dies schmerzhaft sein, wenn es sich in viele separate Dateien/Module ausbreitet. Wenn es sich in eine Funktion ausbreitet, die nicht geändert werden kann (z. B. eine Systembibliothek), ist eine Umwandlung erforderlich. Das Streuen von const in vorhandenen Code ist also möglicherweise problematisch. In neuem Code ist es jedoch am besten, const gegebenenfalls konsistent zu qualifizieren.

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

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

strchr gibt einen char* zurück, keinen const char*. Da sein Aufrufparameter const ist, muss er cast den Aufrufparameter auf char*. Und in diesem Fall wird die echte schreibgeschützte Speichereigenschaft weggeworfen. Bearbeiten: - Dies gilt allgemein für Variablen im Nur-Lese-Speicher. Mit 'ROM' meine ich nicht nur physisch ROM], sondern jeden Speicher, der schreibgeschützt ist, wie es im Codeabschnitt von Programmen der Fall ist, die auf einem typischen Betriebssystem ausgeführt werden.

Viele Standardbibliotheksfunktionen verhalten sich gleich, 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.

74
William Morris

Im Allgemeinen wird in jeder Programmiersprache empfohlen, const oder den entsprechenden Modifikator zu verwenden

  • Es kann dem Anrufer klarstellen, dass sich das, was er übergeben hat, nicht ändern wird
  • Mögliche Geschwindigkeitsverbesserungen, da der Compiler sicher weiß, dass er bestimmte Dinge weglassen kann, die nur relevant sind, wenn sich der Parameter ändern kann
  • Schutz vor versehentlichem Ändern des Wertes
10
TheLQ

Ja, es ist im Grunde die Antwort des 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 mit nur einer Umwandlung leicht ändern.

In dem, was ich normalerweise sehe, wird es meistens verwendet, um konstante Werte in den 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. Erstellen Sie daher eine Kopie der Variablen und übergeben Sie sie an die Funktion. Wenn dies nicht der Fall ist, benötigen Sie die Kopie offensichtlich nicht, sodass Sie beispielsweise Folgendes ä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 mit dem 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 Compilerfehler zu sagen, aber Sie können a nicht als Referenz festlegen zu einer anderen Sache.

1
lgarcia

In Übereinstimmung mit den Aussagen von TheLQ:

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

0
David Otano