Wie verwende ich am besten das Schlüsselwort const in C?

Lesezeit: 7 Minuten

Ich versuche, ein Gefühl dafür zu bekommen, wie ich es verwenden sollte const im C-Code. Zuerst habe ich mich nicht wirklich darum gekümmert, es zu benutzen, aber dann habe ich eine ganze Reihe von Beispielen gesehen const durchgehend verwendet. Soll ich mich anstrengen und zurückgehen und religiös geeignete Variablen machen const? Oder verschwende ich nur meine Zeit?

Ich nehme an, es macht es einfacher zu lesen, welche Variablen sich voraussichtlich ändern werden, insbesondere in Funktionsaufrufen, sowohl für Menschen als auch für den Compiler. Übersehe ich noch andere wichtige Punkte?

  • alles ist sowieso eine Variable. const ist nur, wie Sie sagen, ein Hinweis darauf, dass der zugewiesene Wert nicht geändert werden sollte. aber Sie können mit Zeigern herumspielen und so weiter, um diesen Wert hinter dem Rücken des Compilers zu ändern: stackoverflow.com/questions/3801557/…

    – Markus B

    18. Januar 2013 um 15:16 Uhr

  • Verwandte: Sell me on const correctness (es ist C++, aber auch relevant für C).

    – Netcoder

    18. Januar 2013 um 15:18 Uhr

  • Ich würde mir nicht die Mühe machen, auf Anwendungen zurückzugehen, die funktionieren und mit denen Sie fertig sind. Wenn Sie jedoch Bibliotheken haben, wäre es nicht schlecht, sie zu verwenden const. An manchen Stellen muss man allerdings aufgeben. Zum Beispiel const und mehrdimensionale Arrays funktionieren wirklich schrecklich zusammen.

    – Shahbaz

    18. Januar 2013 um 15:21 Uhr

  • Ja, du hast vollkommen recht, es geht um die Lesbarkeit. Wie @Mark B sagt, ist es einfach genug, den Wert einer Konstante über die Hintertür zu ändern, wenn jemand wollte, also signalisieren Sie im Grunde nur Ihre Absicht. C kann sehr knapp sein, also muss alles, was die Lesbarkeit unterstützt, gut sein.

    – PeteH

    18. Januar 2013 um 15:23 Uhr

  • Die ‘const’-Deklaration von C++: Warum & Wie

    – Grijesh Chauhan

    18. Januar 2013 um 15:42 Uhr

Benutzer-Avatar
dunkel

const ist getippt, #define Makros sind es nicht.

const wird durch den C-Block begrenzt, #define bezieht sich auf eine Datei (genauer gesagt auf eine Kompilationseinheit).

const ist am nützlichsten bei der Parameterübergabe. Wenn du siehst const Wenn Sie es auf einem Prototyp mit Zeigern verwenden, wissen Sie, dass es sicher ist, Ihr Array oder Ihre Struktur zu übergeben, da die Funktion es nicht ändert. Nein const und es kann.

Schauen Sie sich die Definition für solche wie an strcpy() und du wirst sehen was ich meine. Wenden Sie von Anfang an “Konstanz” auf Funktionsprototypen an. Nachrüstung const ist nicht so schwer wie “viel Arbeit” (aber OK, wenn Sie nach Stunden bezahlt werden).

Bedenken Sie auch:

const char *s = "Hello World";
char *s = "Hello World";

was ist richtig und warum?

  • In Ihrem Beispiel würde ich also davon ausgehen, dass ich die nicht ändern kann "Hello World" Teil in der ersten Zeile (aber ich kann machen s auf eine ganz andere Zeichenfolge zeigen), ist das richtig? Ich habe diese Notation auch hier und da gesehen, wie Strings (d. h. Arrays von char) sollte instanziiert werden?

    – c00kiemonster

    18. Januar 2013 um 15:30 Uhr

  • @c00kiemonster: Wenn der Inhalt geändert werden kann, machen Sie es nicht const. Aber im obigen Beispiel s ist eine Konstante und kann daher nicht geändert werden.

    – David Schwartz

    18. Januar 2013 um 15:31 Uhr

  • @c00kiemonster: ja, das erste Beispiel, mit dem const ist richtig. Das zweite Beispiel ist falsch, aber leider üblich. Es würde zu einem Versuch führen, den Nur-Lese-Speicher zu verändern (Absturz!). Vor langer Zeit erlaubte Visual Studio 5 das und gab einige “interessante” Effekte.

    – dunkel

    18. Januar 2013 um 15:42 Uhr

  • @cdarke nein, das zweite Beispiel ist leider korrekt, aber definiert implementiert … Ich hoffe, dass C-Standard eines Tages diese Tatsache ändern wird, da 99% der Compiler dies nicht zulassen. Ich verstehe immer noch nicht, warum der Compiler keine Warnung erzeugt, wenn er die Änderung des Zeichenfolgenliterals als undefiniertes Verhalten definiert.

    – Sternengatter

    26. April 2018 um 6:49 Uhr


  • @Stargateur: Ich nehme an, es hängt davon ab, was Sie mit “richtig” meinen.

    – dunkel

    26. April 2018 um 7:01 Uhr


Benutzer-Avatar
PP

Wie verwende ich am besten das Schlüsselwort const in C?

Verwenden const wann du es machen willst “schreibgeschützt”. So einfach ist das 🙂

Verwenden const ist nicht nur eine gute Praxis, sondern verbessert auch die Lesbarkeit und Verständlichkeit des Codes und hilft, einige häufige Fehler zu vermeiden. Verwenden Sie auf jeden Fall const, wo es angebracht ist.

Benutzer-Avatar
Lewis Kelsey

Abgesehen davon, dass es beim Versuch, die Konstante zu ändern, einen Compilerfehler erzeugt und die Konstante als nicht konstanten Parameter weitergibt und somit als Compilerwächter fungiert, ermöglicht es dem Compiler auch, bestimmte Optimierungen durchzuführen, da er weiß, dass sich der Wert nicht ändern wird und dies daher möglich ist cachen Sie den Wert und müssen ihn nicht frisch aus dem Speicher lesen, da er sich nicht geändert hat, und es ermöglicht, ihn sofort im Code zu ersetzen.

C konst

const und register sind im Grunde das Gegenteil von volatile und verwenden volatile überschreibt die const-Optimierungen im Datei- und Blockbereich und die register Optimierungen im Blockbereich. const register und register erzeugt identische Ausgaben, da const nichts auf C im Blockbereich auf gcc C -O0 tut und auf -O1 und höher redundant ist, also nur die register Optimierungen gelten bei -O0 und sind ab -O1 redundant.

#include<stdio.h>

int main() {
    const int i = 1;
    printf("%d", i);
}
.LC0:
  .string "%d"
main:
  push rbp
  mov rbp, rsp
  sub rsp, 16
  mov DWORD PTR [rbp-4], 1
  mov eax, DWORD PTR [rbp-4] //load from stack isn't eliminated for block-scope consts on gcc C unlike on gcc C++ and clang C, even though value will be the same
  mov esi, eax
  mov edi, OFFSET FLAT:.LC0
  mov eax, 0
  call printf
  mov eax, 0
  leave
  ret

In diesem Fall mit -O0, const, volatile und auto alle produzieren den gleichen Code, mit nur register abweichend vgl

#include<stdio.h>
const int i = 1;
int main() {
    printf("%d", i);
}
i:
  .long 1
.LC0:
  .string "%d"
main:
  push rbp
  mov rbp, rsp
  mov eax, DWORD PTR i[rip] //load from memory
  mov esi, eax
  mov edi, OFFSET FLAT:.LC0
  mov eax, 0
  call printf
  mov eax, 0
  pop rbp
  ret

mit const int i = 1; stattdessen:

i:
  .long 1
.LC0:
  .string "%d"
main:
  push rbp
  mov rbp, rsp
  mov eax, 1  //saves load from memory, now immediate
  mov esi, eax
  mov edi, OFFSET FLAT:.LC0
  mov eax, 0
  call printf
  mov eax, 0
  pop rbp
  ret

C++-Konstante

#include <iostream>

int main() {
    int i = 1;
    std::cout << i;
}
main:
  push rbp
  mov rbp, rsp
  sub rsp, 16
  mov DWORD PTR [rbp-4], 1 //stores on stack
  mov eax, DWORD PTR [rbp-4] //loads the value stored on the stack
  mov esi, eax
  mov edi, OFFSET FLAT:_ZSt4cout
  call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
  mov eax, 0
  leave
  ret

#include <iostream>

int main() {
    const int i = 1;
    std::cout << i;
}
main:
  push rbp
  mov rbp, rsp
  sub rsp, 16
  mov DWORD PTR [rbp-4], 1 //stores it on the stack
  mov esi, 1               //but saves a load from memory here, unlike on C
                           //'register' would skip this store on the stack altogether
  mov edi, OFFSET FLAT:_ZSt4cout
  call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
  mov eax, 0
  leave
  ret

#include <iostream>
int i = 1;
int main() {

    std::cout << i;
    }
i:
  .long 1
main:
  push rbp
  mov rbp, rsp
  mov eax, DWORD PTR i[rip] //load from memory
  mov esi, eax
  mov edi, OFFSET FLAT:_ZSt4cout
  call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
  mov eax, 0
  pop rbp
  ret

#include <iostream>
const int i = 1;
int main() {

    std::cout << i;
    }
main:
  push rbp
  mov rbp, rsp
  mov esi, 1 //eliminated load from memory, now immediate
  mov edi, OFFSET FLAT:_ZSt4cout
  call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
  mov eax, 0
  pop rbp
  ret

C++ hat die zusätzliche Einschränkung, einen Compilerfehler zu erzeugen, wenn a const ist nicht initialisiert (sowohl im Dateibereich als auch im Blockbereich). const hat auch eine interne Verknüpfung als Standard in C++. volatile immer noch überlagert const und register aber const register kombiniert beide Optimierungen auf C++.

Auch wenn der gesamte obige Code mit dem standardmäßigen impliziten -O0 kompiliert wird, wenn er mit -Ofast kompiliert wird, const überraschenderweise immer noch nicht redundant in C oder C++ auf clang oder gcc für dateibezogen consts. Das Laden aus dem Speicher wird nicht optimiert, es sei denn const wird verwendet, auch wenn die Dateibereichsvariable im Code nicht geändert wird. https://godbolt.org/z/PhDdxk.

1115100cookie-checkWie verwende ich am besten das Schlüsselwort const in C?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy