Ich stelle zunächst fest, dass, obwohl ich hier nur "C" erwähne, dasselbe auch für C ++ gilt.
Der Kommentar, in dem Godel erwähnt wurde, war teilweise (aber nur teilweise) zutreffend.
Wenn Sie es, nicht definiertes Verhalten in den C - Normen wird herunterkommen weitgehend unter Hinweis darauf , nur die Grenze zwischen dem, was die Standard - Versuche zu definieren, und was nicht.
Gödels Theoreme (es gibt zwei) besagen grundsätzlich, dass es unmöglich ist, ein mathematisches System zu definieren, das (durch seine eigenen Regeln) als vollständig und konsistent nachgewiesen werden kann. Sie können Ihre Regeln so formulieren, dass sie vollständig sind (der Fall, mit dem er sich befasst hat, waren die "normalen" Regeln für natürliche Zahlen), oder Sie können es ermöglichen, ihre Konsistenz zu beweisen, aber Sie können nicht beide haben.
Bei etwas wie C gilt dies nicht direkt - für die meisten Sprachdesigner hat die "Beweisbarkeit" der Vollständigkeit oder Konsistenz des Systems zum größten Teil keine hohe Priorität. Zugleich wurden sie wahrscheinlich (zumindest teilweise) dadurch beeinflusst, dass sie wussten, dass es nachweislich unmöglich ist, ein "perfektes" System zu definieren - eines, das nachweislich vollständig und konsistent ist. Zu wissen, dass so etwas unmöglich ist, könnte es ein bisschen einfacher gemacht haben, einen Schritt zurückzutreten, ein wenig zu atmen und die Grenzen dessen zu bestimmen, was sie zu definieren versuchen würden.
Unter der Gefahr, (erneut) der Arroganz beschuldigt zu werden, würde ich den C-Standard als (teilweise) von zwei Grundgedanken bestimmt bezeichnen:
- Die Sprache sollte eine möglichst große Auswahl an Hardware unterstützen (idealerweise alle "vernünftigen" Hardware bis zu einer angemessenen Untergrenze).
- Die Sprache sollte das Schreiben einer möglichst großen Auswahl an Software für die jeweilige Umgebung unterstützen.
Das erste bedeutet, dass, wenn jemand eine neue CPU definiert, es möglich sein sollte, eine gute, solide und brauchbare Implementierung von C dafür bereitzustellen, solange das Design zumindest einigermaßen in der Nähe einiger einfacher Richtlinien liegt - im Grunde genommen, wenn dies der Fall ist Es folgt etwas der allgemeinen Ordnung des Von Neumann-Modells und bietet mindestens eine angemessene Mindestmenge an Speicher, die ausreichen sollte, um eine C-Implementierung zu ermöglichen. Für eine "gehostete" Implementierung (eine, die auf einem Betriebssystem ausgeführt wird) müssen Sie einen Begriff unterstützen, der Dateien ziemlich genau entspricht, und über einen Zeichensatz mit einer bestimmten Mindestanzahl von Zeichen verfügen (91 sind erforderlich).
Die zweite Mittel soll es möglich sein , Code zu schreiben, die Hardware direkt manipuliert, so können Sie Dinge wie Bootloader, Betriebssysteme, Embedded - Software schreiben , die ohne O läuft, usw. Es gibt schließlich einige Grenzen in dieser Hinsicht so fast jeder praktisches Betriebssystem, Bootloader, usw., ist wahrscheinlich zumindest eine enthalten wenig in Assembler geschrieben Stück Code. In ähnlicher Weise wird wahrscheinlich sogar ein kleines eingebettetes System mindestens eine Art von vorab geschriebenen Bibliotheksroutinen enthalten, um den Zugriff auf Geräte auf dem Hostsystem zu ermöglichen. Obwohl es schwierig ist, eine genaue Grenze zu definieren, besteht die Absicht darin, die Abhängigkeit von solchem Code auf ein Minimum zu beschränken.
Das undefinierte Verhalten in der Sprache wird hauptsächlich durch die Absicht bestimmt, dass die Sprache diese Funktionen unterstützt. Mit der Sprache können Sie beispielsweise eine beliebige Ganzzahl in einen Zeiger umwandeln und auf alles zugreifen, was sich an dieser Adresse befindet. Der Standard unternimmt keinen Versuch zu sagen, was passieren wird, wenn Sie dies tun (z. B. kann das Lesen von einigen Adressen äußerlich sichtbare Auswirkungen haben). Zugleich macht es keinen Versuch zu verhindern , dass Sie solche Dinge zu tun, weil Sie brauchen für einige Arten von Software , die Sie angeblich sind in der Lage sein , in C zu schreiben
Es gibt auch undefiniertes Verhalten, das von anderen Designelementen gesteuert wird. Eine weitere Absicht von C ist beispielsweise, die separate Kompilierung zu unterstützen. Dies bedeutet (zum Beispiel), dass Sie Teile mit einem Linker "verknüpfen" können, der in etwa dem entspricht, was die meisten von uns als das übliche Modell eines Linkers ansehen. Insbesondere soll es möglich sein, separat kompilierte Module ohne Kenntnis der Semantik der Sprache zu einem vollständigen Programm zusammenzufassen.
Es gibt eine andere Art von undefiniertem Verhalten (das in C ++ weitaus häufiger vorkommt als in C), das nur aufgrund der Grenzen der Compilertechnologie auftritt - Dinge, von denen wir im Grunde wissen, dass sie Fehler sind, und die der Compiler wahrscheinlich als Fehler diagnostizieren soll. Angesichts der derzeitigen Grenzen der Compilertechnologie ist es jedoch zweifelhaft, ob sie unter allen Umständen diagnostiziert werden können. Viele davon werden von den anderen Anforderungen bestimmt, z. B. für die getrennte Kompilierung. Daher geht es hauptsächlich darum, widersprüchliche Anforderungen auszugleichen. In diesem Fall hat sich das Komitee im Allgemeinen für die Unterstützung größerer Fähigkeiten entschieden, auch wenn dies bedeutet, dass einige mögliche Probleme nicht diagnostiziert wurden. anstatt die Möglichkeiten einzuschränken, um sicherzustellen, dass alle möglichen Probleme diagnostiziert werden.
Diese Absichtsunterschiede führen zu den meisten Unterschieden zwischen C und Java oder den CLI-basierten Systemen von Microsoft. Letztere beschränken sich ausdrücklich auf die Arbeit mit einer viel engeren Hardware oder erfordern Software, um die spezifischere Hardware zu emulieren, auf die sie abzielen. Sie beabsichtigen außerdem ausdrücklich, direkte Manipulationen an der Hardware zu verhindern. Stattdessen müssen Sie JNI oder P / Invoke (und in C geschriebenen Code) verwenden, um einen solchen Versuch zu unternehmen.
Wenn wir für einen Moment auf Godels Theoreme zurückkommen, können wir eine Parallele ziehen: Java und CLI haben sich für die "intern konsistente" Alternative entschieden, während C sich für die "vollständige" Alternative entschieden hat. Natürlich ist dies eine sehr grobe Analogie - jemand hat versucht , einen formalen Beweis Ich bezweifle , entweder interne Konsistenz oder Vollständigkeit in jedem Fall. Trotzdem passt der allgemeine Begriff ziemlich gut zu den Entscheidungen, die sie getroffen haben.