
Kurzum: weil wir es gesagt haben.
:)
Okay, das ist eine zu kurze Erklärung für den Artikel, lieber Leser, und meine provokanten Worte erfordern eine Erklärung.
Die Sitzung des C-Sprachkomitees, die ursprünglich in Freiburg stattfinden sollte, aber aus offensichtlichen Gründen nicht zusammenwuchs, endete am 7. August. Es ist gut gelaufen, wir haben an allen Fronten Fortschritte gemacht. Ja, wir machen tatsächlich Fortschritte, das versichere ich Ihnen, und C ist nicht tot.
Ich werde auch erwähnen, dass ich der Herausgeber des C-Projekts geworden bin. Bevor ich den Titel als ignorante Aussage von jemandem betrachte, der zu faul ist, um "zu versuchen, sich zu verbessern", möchte ich Ihnen versichern, dass ich tatsächlich sehr hart arbeite, damit C dies kann um die Bedürfnisse von Entwicklern zu befriedigen, ohne 50 spezifische Erweiterungen verschrauben zu müssen, um mehr oder weniger schöne und nützliche Bibliotheken und Anwendungen zu erstellen.
Und doch habe ich es gesagt (dass die C-Sprache Sie niemals davon abhalten wird, Fehler zu machen), was bedeutet, dass ich es rechtfertigen muss. Wir können Tausende von CVEs und zugehörigen Tickets mit einer Reihe von C-Codes anzeigen oder MISRA veranlassen, jedes einzelne C-Feature gründlich auf möglichen Missbrauch zu überprüfen ( Hallo, K & R-Prototypdeklarationen)...) oder komplexere und witzigere Fehler im Zusammenhang mit Portabilität und undefiniertem Verhalten. Stattdessen lesen wir die Originalquelle - was der Ausschuss selbst gesagt hat.
Oh, es ist Zeit, Popcorn zu holen ?!
Nein, lieber Leser, legen Sie das Popcorn beiseite. Wie bei allen ISO-Verfahren kann ich die Worte anderer nicht zitieren, und dieser Artikel soll niemanden beschämen. Aber ich werde erklären, warum etwas, das wir in einem standardkonformen ISO C-Dokument leicht als schlechtes Verhalten betrachten könnten, niemals ausgeschlossen werden kann. Beginnen wir mit dem Dokument von Dr. Philipp Klaus Krause:
N2526, verwenden Sie const für Bibliotheksdaten, die nicht geändert werden .
N2526 ist ein sehr einfaches Dokument.
, , , . — , ! …
Ich stimme zu, es ist nicht genau dasselbe, aber ich bin sicher, dass Ihnen die Idee vernünftig erscheinen wird, lieber Leser. Als dieses Dokument zur Abstimmung gestellt wurde, gab es fast keine Stimmen dagegen. Später haben mehrere Personen heftig Einwände erhoben, weil dieser Vorschlag den alten Code gebrochen hat. Das ist natürlich schlecht: Sogar ich nehme den Atem, wenn ich über das Hinzufügen nachdenke
const? Es gibt kein ABI in der C-Sprache, das durch Innovation beeinflusst werden kann. C (seine Implementierung) achtet nicht einmal auf Qualifikanten, wie können wir etwas brechen ?! Werfen wir einen Blick darauf, warum manche Leute glauben, dass dies eine bahnbrechende Veränderung sein wird.
Sprache C.
Oder, wie ich es gerne nenne: "Typensicherheit ist für fehlerhafte Sprachen." Ja, zu ausführlich, also hören wir bei "C" auf. Sie fragen sich vielleicht, warum ich sage, dass Sprachen wie C nicht typsicher sind. Immerhin ist hier:
struct Meow {
int a;
};
struct Bark {
double b;
void* c;
};
int main (int argc, char* argv[]) {
(void)argc;
(void)argv;
struct Meow cat;
struct Bark dog = cat;
// error: initializing 'struct Bark' with an expression of incompatible type 'struct Meow'
return 0;
}
Um ehrlich zu sein, sieht das für mich nach starker Typensicherheit aus, Jim! Und so wird alles noch pikanter:
#include <stdlib.h>
struct Meow {
int a;
};
struct Bark {
double b;
void* c;
};
int main (int argc, char* argv[]) {
(void)argc;
(void)argv;
struct Meow* p_cat = (struct Meow*)malloc(sizeof(struct Meow));
struct Bark* p_dog = p_cat;
// :3
return 0;
}
Ja, der C-Standard erlaubt es zwei völlig unabhängigen Zeigertypen, aufeinander zu verweisen. Die meisten Compiler werden Sie davor warnen, aber der Standard verlangt, dass Sie diesen Code akzeptieren, es sei denn, Sie entspannen
-Werror -Wall -Wpedanticsich usw. usw. usw. usw.
Tatsächlich kann der Compiler dies ohne explizites Casting akzeptieren:
volatile(Wer braucht diese Semantik überhaupt ?!)const(Schreiben Sie hier alle schreibgeschützten Daten!)_Atomic(Gewindesicherheit!)
Ich sage nicht, dass Sie das alles nicht können sollten. Aber wenn Sie in C schreiben - in dem es sehr einfach ist, eine Funktion von 500-1000 Zeilen mit völlig unverständlichen Variablennamen zu erstellen - Infa Sotka, dass Sie hauptsächlich mit Zeigern arbeiten und im Allgemeinen keine Sicherheit in Bezug auf die Basissprache haben. Hinweis: Dies verstößt gegen die Einschränkungen, aber es wurde bereits so viel alter Code geschrieben, dass jede Implementierung Qualifizierer irgendwie ignoriert. Aus diesem Grund wird Ihr Code nicht am Kompilieren gehindert ( danke @fanf!)! In dieser Situation können Sie jeden potenziellen Fehler mithilfe des Compilers leicht identifizieren und erhalten Warnungen. Sie müssen jedoch keine Eingaben vornehmen, um dem Compiler mitzuteilen, was Sie wirklich tun wollten. Noch wichtiger ist jedoch, dass die Menschen, die nach Ihnen kommen, auch nicht verstehen, was Sie vorhaben.
Alles, was Sie tun müssen, ist, die Funktion zu entfernen
-Werror -Wall -Wpedantic, und Sie sind bereit, die Verbrechen des Multithreading, des Nur-Lese-Modus und der Hardware-Register zu begehen.
Es ist jetzt alles fair, oder? Wenn jemand all diese Warn- und Fehlerflags entfernt, ist es ihm egal, welche Art von Fehltritten oder dummen Dingen Sie tun. Dies bedeutet, dass diese Warnungen letztendlich für die Einhaltung der ISO C-Norm völlig irrelevant und harmlos sind. Und doch ...
Wir erwägen, Warnungen zu brechen
Ja.
Dies ist eine besondere Hölle, an die C-Entwickler und in geringerem Maße C ++ - Entwickler gewöhnt sind. Warnungen sind ärgerlich und, wie die Praxis zeigt, einschließlich
-Weverythingoder /W4sehr ärgerlich. Ausblenden von Variablenwarnungen im globalen Namespace (danke, jetzt sind alle Header und C-Bibliotheken ein Problem), Verwenden von "reservierten" Namen (wie die Kinder sagen, " lol nice one xd !! ") und "Diese Struktur ist aufgefüllt." weil Sie verwendet haben alignof"(... ja, ja, ich weiß, dass sie Polsterung hat, ich habe ausdrücklich um mehr Polsterung gebeten, WEIL ICH BENUTZTE alignof, MR. COMPILATOR) - all dies nimmt viel Zeit in Anspruch.
Aber das sind Warnungen.
Selbst wenn sie nerven, helfen sie Ihnen, Probleme zu vermeiden. Die Tatsache, dass ich alle Qualifikationsmerkmale schamlos ignorieren und alle Arten von Lese-, Schreib-, Streaming- und Nur-Lese-Sicherheit vernachlässigen kann, ist ein wichtiges Anliegen, wenn es darum geht, meine Absichten zu kommunizieren und Fehler zu vermeiden. Sogar die alte K & R-Syntax führte zu Fehlern in Industrie- und Regierungscodebasen, weil Benutzer etwas falsch machten. Und sie taten dies nicht, weil sie miese Programmierer waren, sondern weil sie mit Codebasen arbeiten, die oft älter sind als sie, und sich darauf vorbereiten, mit diesen zu kämpfen. lange Millionen von Zeilen. Es ist unmöglich, die gesamte Codebasis im Kopf zu behalten: Konventionen, statische Analysen, allgemeine Warnungen und andere Tools sind dafür. Leider,
Jeder möchte einen Code ohne Warnungen haben.
Dies bedeutet, dass, wenn der GCC-Entwickler Warnungen für potenziell problematische Situationen empfindlicher macht, Betreuer (nicht die ursprünglichen Entwickler) unerwartet fette Protokolle von mehreren Gigabyte aus dem alten Code erhalten, die viele neue Warnungen und alle möglichen anderen Dinge enthalten. "Das ist Idiotie", sagen sie, "der Code hat JAHRE funktioniert. Warum beschwert sich GCC jetzt?" Das heißt, selbst wenn Sie
constder Signatur Funktionen hinzufügen , selbst wenn diese moralisch, spirituell und tatsächlich korrekt sind, wird dies vermieden. "Menschen brechen" bedeutet "jetzt müssen sie nach einem Code suchen, der zweifelhafte Absichten hat." Dies ist Code, der - unter Androhung eines undefinierten Verhaltens - Ihren Chip zerstören oder Ihren Speicher beschädigen kann.... Dies ist jedoch ein weiteres Problem, das heutzutage den Beruf des C-Entwicklers begleitet.
Alter als Qualitätsmaßstab
Wie viele Menschen haben sogar angenommen, dass sie
sudoeine so primitive Sicherheitslücke wie "-1 oder ein ganzzahliger Überlauf ermöglichen den Zugriff auf alles" haben? Wie viele Leute dachten, Heartbleed könnte ein echtes Problem sein? Wie viele Spieleentwickler liefern „kleine“ stb-Bibliotheken aus, ohne einen Phaser zu verwenden, ohne zu bemerken, dass diese Bibliotheken wichtigere Eingabeschwachstellen enthalten, als Sie sich vorstellen können? Ich kritisiere nicht alle diese Entwicklungen oder ihre Autoren: Sie leisten uns wichtige Hilfe, von der die Welt jahrzehntelang abhängig war, oft mit wenig oder keiner Unterstützung, bis ein großes Problem auftritt. Aber Menschen, die diese Entwicklungen vergöttern und selbstständig machen, versprühen dann ein giftiges Sprichwort von sich selbst, das den Fehler des Überlebenden veranschaulicht:
, ?
Menschen, die in dieser Branche lange genug überleben, beginnen, Alter und Qualität gleichzusetzen, so wie Codebasen Weinfässer sind. Dabei werden die Prinzipien der Abwärtskompatibilität beibehalten und als die höchsten Ideale von C "entspannt". Je älter und länger der Code verwendet wird, desto feiner und raffinierter wird der Wein.
Leider ist nicht alles so romantisch und niedlich: voller Fehler, mit einer Fülle von Sicherheitslücken, all diese technischen Schulden werden von Tag zu Tag gefährlicher. Im Laufe der Zeit verwandeln sich alle Systeme in halbherzige, ungepflegte und teilweise nicht unterstützte verrottende Haufen. Sie sind verschönert und haben einen Geist des Adels, aber in Wirklichkeit sind sie Mumien, die nur darauf warten, unbeholfen gestoßen zu werden, und dann werden ihre eiternden, antidiluvianischen Furunkel explodieren und Ihre Anwendung mit ihrem schönen, erfahrenen Botulismus überfluten.
Hmm ... widerlich. Aber was ist mit Standard C?
Das Problem, das ich während meiner (unglaublich kurzen) Amtszeit als Besprechungsteilnehmer festgestellt habe, ist, dass wir die Abwärtskompatibilität in den Vordergrund stellen. Für diejenigen, die heute sogar auf C migrieren, halten wir an alten Anwendungen und ihren Anwendungsfällen fest und berauben uns der Möglichkeit, die Sicherheit oder Kunstfertigkeit des C-Codes zu verbessern. kann er sie ausschalten. Diese Warnungen, nicht Fehler, sind nicht umsonst: Eine abstrakte C-Maschine benötigt keineFür die Diagnose ermöglicht ISO C, dass ein solcher Code in strengen Montagemodi akzeptiert wird. Und das würde der ganzen Welt helfen, sich von APIs zu lösen, die offen sagen: "Das Ändern des Inhalts, den wir Ihnen zur Verfügung stellen, ist undefiniertes Verhalten."
Wir haben jedoch unsere Meinung zu diesem Dokument geändert, nachdem es als Grund angegeben wurde, „wir können keine neuen Warnungen einführen“.
Das Argument gegen den Vorschlag war: "Es ist so viel Code geschrieben, der kaputt geht, wenn wir diese Signaturen ändern." Dies beschränkt wiederum Änderungen an Warnungen in Bezug auf das Fehlerverhalten (denken Sie daran, implizite Konvertierungen, die Qualifizierer entfernen - sogar
_Atomic- voll gültig nach ISO C, auch wenn sie gegen die Beschränkungen verstoßen). Wenn dies der Fall wäre, würde jeder Compilerautor so etwas wie Ages in Rust, nur für Warnungen, einführen, um den Leuten einen "stabilen" Benchmark zum Testen zu geben. Dieser Vorschlag ist nicht neu: Ich habe ähnliche Dokumente von Coverity-Ingenieuren gelesen, in denen es darum geht, neue Warnungen zu generieren und wie Benutzer darauf reagieren. Es ist schwierig, das "Vertrauen" der Entwickler in neue Warnungen und andere Dinge zu verwalten. Es dauert lange, die Menschen von ihrer Nützlichkeit zu überzeugen. Auch hatte John Carmack hart arbeiten , um die richtige Menge von Warnungen und Fehlern aus seinen statischen Analysetool zu bekommen , um seine Entwicklung anzupassen, bevor er festgestellt , dass es wäre „unverantwortlich , dies nicht zu verwenden . “
Dennoch haben wir, der Ausschuss, nicht zugestimmt,
constden vier Funktionen wertschöpfende Funktionen hinzuzufügen, da dies dem potenziell gefährlichen Code Warnungen hinzufügen würde. Wir haben Einwände gegen die Ablehnung der alten K & R-Syntax erhoben, obwohl sowohl unschuldige Versehen als auch schwerwiegende Schwachstellen bei der Übergabe der falschen Typen nachgewiesen wurden. Wir haben dem Präprozessor fast undefiniertes Verhalten hinzugefügt, nur um es herunterzufahren, aber um die C-Implementierung "so zu verhalten, wie sie sollte". Aufgrund der Abwärtskompatibilität gehen wir immer am Rande, um offensichtliche Fehler zu vermeiden. Und das, lieber Leser, macht mir am meisten Angst vor der Zukunft von S.
Standard C schützt Sie nicht
Machen Sie keinen Fehler: Es spielt keine Rolle, was die Programmierer Ihnen sagen oder was sie Ihnen zuflüstern. Der Lenkungsausschuss in C-Sprache ist sehr klar. Wir werden Ihrem alten Code keine neuen Warnungen hinzufügen, auch wenn dieser Code gefährlich sein könnte. Wir werden Sie nicht davon abhalten, Fehler zu machen, da dies die Vorstellung untergraben kann, wie Ihr alter Code funktioniert, was falsch ist. Wir werden Neulingen nicht helfen, besseren C-Code zu schreiben. Wir werden nicht verlangen, dass Ihr alter Code einem Standard entspricht. Jede neue Funktion ist optional, da wir uns nicht vorstellen können, Compilerautoren zu zwingen, sich an einen höheren Standard zu halten oder mehr von unseren Standardbibliotheksentwicklern zu erwarten.
Wir lassen den Compiler Sie anlügen. Wir werden Ihren Code anlügen. Und wenn alles schief geht - es wird ein Fehler auftreten, "Oh, es ist eine Art Müll passiert", wird es ein Datenleck geben - werden wir feierlich den Kopf schütteln. Wir werden unsere Ideen teilen und für Sie beten und sagen: "Nun, was für eine Schande." In der Tat, schade ...
Vielleicht werden wir es eines Tages beheben, lieber Leser.