Warum deklarieren main als ein array zusammenstellen?
Sah ich ein code-snippet auf CodeGolf vorgesehen, da ein compiler-Bombe, wo main
ist deklariert als ein großes array. Ich habe versucht, die folgenden (nicht die Bombe) version:
int main[1] = { 0 };
Scheint es zu kompilieren einwandfrei unter Clang und mit nur ein warning unter GCC:
warning: 'main' ist in der Regel eine Funktion [-Wmain]
Die resultierende binäre ist natürlich Müll.
Aber warum tut man es kompilieren überhaupt? Ist es überhaupt erlaubt, die von der C-Spezifikation? Der Abschnitt, den ich denke, relevant ist, sagt:
5.1.2.2.1 Programmstart
Die Funktion, die aufgerufen wird bei Programm-Start ist mit dem Namen main. Die Umsetzung erklärt kein Prototyp für diese Funktion. Es muss festgelegt werden mit dem Rückgabetyp int und ohne Parameter [...] oder mit zwei Parametern, [ ... ] oder in einem anderen von der Implementierung definierte Art und Weise.
Bedeutet "etwas andere Umsetzung definierter Weise" gehören ein globales array? (Es scheint mir, dass die Skillung bezieht sich noch auf eine Funktion.)
Wenn nicht, ist es eine compiler-Erweiterung? Oder eine Funktion des toolchains, das dient einem anderen Zweck, und Sie beschlossen, es durch das frontend?
- Es nicht kompilieren. ISO-C verbietet zero sized arrays.
- Es ist nicht gestattet, die von der C-Spezifikation. Compiler oft implementieren Sachen, die nicht Gegenstand der Spezifikation.
- Verwandte Frage: Wie kann ein Programm mit einer globalen variable namens main statt einer main-Funktion zu arbeiten?. Ich denke, auch inspiriert durch einen codegolf Frage.
- Besonders in der Fall of Malbolge
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ist es denn C erlaubt "nicht gehostete" oder freistehende Umwelt, die nicht erfordern den
main
Funktion. Dies bedeutet, dass der namemain
ist frei für andere Verwendungen. Dies ist der Grund, warum die Sprache als solche können für solche Erklärungen. Die meisten Compiler unterstützen beide (der Unterschied ist meist, wie die Verknüpfung erfolgt) und Sie deshalb nicht verbieten Konstrukte, die illegal in der gehosteten Umgebung.Dem Abschnitt bezieht sich auf die in der Norm bezieht sich auf hosted-Umgebung, die entsprechend für freistehende ist:
Wenn Sie dann verknüpfen Sie es wie gewohnt wird es schlecht gehen, da der linker hat in der Regel wenig wissen über die Natur der Symbole (welche Art es ist oder sogar, wenn es einer Funktion oder Variablen). In diesem Fall wird der linker glücklich aufzulösen Anrufe zu
main
um die variable mit dem Namenmain
. Wenn das symbol nicht gefunden, es wird Ergebnis in der link-Fehler.Wenn Sie einen Hyperlink wie gewohnt, Sie sind im Grunde versucht, zu verwenden, der compiler im gehosteten Betrieb und dann nicht definieren
main
als Sie eigentlich bedeutet Undefiniertes Verhalten gemäß Anhang J. 2:Den Zweck der freistehende Möglichkeit ist der Einsatz von C in Umgebungen, in denen (zum Beispiel) standard-Bibliotheken oder CRT-Initialisierung ist nicht gegeben. Dies bedeutet, dass der code, der ausgeführt wird, bevor
main
genannt wird (das ist die CRT-Initialisierung, Initialisierung der C-runtime) kann nicht zur Verfügung gestellt, und Sie würde erwartet werden, dass Sie sich (und Sie können beschließen, einemain
oder kann man nicht entscheiden).int f(int argc,char **argv) { return 0; } char *main = (char *)f;
main
die ist, wo der Zeiger gespeichert ist, und nicht das, was es Punkte an.namespace Main_abused { class Program { int Main = 0; } }
. Es ist eher, dass die Haupt - (und Main in C#) sind keine Schlüsselwörter, und die C-linkers dumm sind, äh, einfach.main
nicht definiert wird in einer Weise anders aus, was von der Norm geforderten (oder der Durchführung angegeben) ist fehlerhaft.Wenn Sie daran interessiert sind, wie Programm erstellen Sie in der main-array: https://jroweboy.github.io/c/asm/2015/01/26/when-is-main-not-a-function.html. Der Beispiel-Quellcode enthält nur einen char (und später int) array, genannt
main
die gefüllt ist mit der Maschine Anweisungen.Die wichtigsten Schritte und Probleme waren:
main[]
ausführbare Datei, indem Sie deklarieren const (Daten werden anscheinend entweder beschreibbar oder ausführbar)Die resultierende C-code ist nur
aber die Ergebnisse in ein ausführbares Programm auf einem 64-bit-PC:
Das problem ist, dass
main
ist kein reservierter Bezeichner. Der C-standard sagt nur, dass bei gehosteten Systemen gibt es normalerweise eine Funktion, die aufgerufen wird main. Aber nichts in der Norm verhindert, dass Sie missbraucht die gleichen Bezeichner für andere finstere Zwecke.GCC gibt Ihnen ein selbstgefälliger Warnung "main ist in der Regel eine Funktion", deutete an, dass die Verwendung des Bezeichners
main
für andere, nicht Verwandte Zwecke ist nicht eine geniale Idee.Dummes Beispiel:
Dieses Programm wird wiederholt drucken Sie die Ziffern 5,4,3,2,1, bis es einen stack overflow und stürzt ab (don ' T try this at home). Leider, das obige Programm ist ein streng konformes C-Programm und der compiler kann Sie nicht daran hindern, es zu schreiben.
main
ist - nach dem kompilieren - nur ein anderes symbol in ein Objekt-Datei, wie viele andere (Globale Funktionen, Globale Variablen, etc).Den linker verknüpft wird, das symbol
main
unabhängig von seinem Typ. In der Tat, der linker kann nicht sehen, den Typ des symbols an alle (er kann sehen, dass es nicht in der.text
-Abschnitt, aber das ist ihm egal ;))Gcc verwenden, ist der standard-Einstieg ist _start, die wiederum Aufrufe von main() nach der Erstellung der runtime-Umgebung. So springt er an die Adresse der integer-array, die in der Regel führt eine ungültige Anweisung, segfault oder einige andere schlechte Verhalten.
Dies alles natürlich nichts zu tun hat mit dem C-standard.
Es nur kompiliert, weil Sie nicht die richtigen Optionen (und funktioniert, weil linkers manchmal nur die Sorge für die Namen von Symbolen, die nicht Ihre Typ).
main
ist in der Regel eine Funktion (dann geht es weiter und links sowieso).-Werror
dann.-Wno-*
für die Warnungen, die Sie gewählt haben, zu akzeptieren. Mehr als oft nicht, die Warnungen sind einfach zu beheben, und wenn Sie nicht, etwas falsch ist mit dem code, IMNSHO. Ich benutze-Werror
für Jahre jetzt, und es hat bewährt. Die neuen Warnungen sind nicht zu übersehen und müssen behoben werden, um fortzufahren.-Werror
und aktivieren von Warnungen ist eine gute Idee, aber das widerspricht nicht der Tatsache, dass dies so wird der compiler andernfalls zu kompilieren gültigen C-Programme.-Werror
ist zu fail compilation wenn eine Warnung ausgegeben wird. Warnungen können ausgegeben werden, auf die gültigen C-Programme. Ich bin ziemlich sicher, dass die GCC-Entwickler nicht wollen, um einen Blick auf, die.Dieser wird kompiliert und ausgeführt, auf x86_64... macht nichts, nur zurückgeben 😀