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?
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?
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.
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.
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 Beispielconst
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