Warum ist die Größe einer Funktion in C immer 1 Byte?

87

Wenn wir die Größe einer Funktion mit überprüfen sizeof(), erhalten wir immer 1 Byte . Was bedeutet dieses 1 Byte?

user1645461
quelle

Antworten:

80

Es ist eine Beschränkung verletzt, und der Compiler sollte es diagnostizieren. Wenn es es trotzdem kompiliert, hat Ihr Programm ein undefiniertes Verhalten [danke an @Steve Jessop für die Klärung des Fehlermodus und siehe @ Michael Burrs Antwort, warum einige Compiler dies zulassen]: Ab C11, 6.5.3.4./ 1:

Der sizeofOperator darf nicht auf einen Ausdruck mit Funktionstyp angewendet werden

Kerrek SB
quelle
11
Dies ist eine Einschränkung, was bedeutet, dass sie in einem konformen Compiler diagnostiziert wird. Wenn der Compiler es trotzdem kompiliert (nachdem er es diagnostiziert hat), ist das Verhalten undefiniert. Wenn der Compiler dies nicht diagnostiziert (was beispielsweise bei gcc nicht der Fall ist -pedantic), haben Sie einen nicht konformen Compiler und jedes Programm hat ein undefiniertes Verhalten.
Steve Jessop
1
Das Verhalten ordnet es in dieselbe Kategorie wie eine GNU C-Erweiterung ein, aber ich habe keine Ahnung, warum jemand dieses Verhalten wünscht , daher weiß ich nicht, warum die GNU-Autoren sich Mühe gegeben haben, es hinzuzufügen.
Steve Jessop
1
@SteveJessop: Beachten Sie, dass dies gerade ist -std=c11, nicht gnu11 . Dies ist eine wirklich seltsame Compiler-Erweiterung.
Kerrek SB
6
Oh! Ich wette, es geht darum, die Arithmetik für Funktionszeiger zu aktivieren, genauso wie sizeof(void)1 in GNU C.
Steve Jessop
3
In Bezug auf -std=c11: Jemand sollte die -std=c*Optionen auf Werbestandards verweisen . Sie aktivieren den Konformitätsmodus nicht, sondern deaktivieren lediglich Erweiterungen, die das Kompilieren eines wohlgeformten Programms verhindern würden (z. B. typeofein Schlüsselwort, da ein wohlgeformtes C-Programm es als Variablennamen verwenden kann, dies jedoch gccstandardmäßig ablehnen würde ). Um Erweiterungen zusätzlich zu deaktivieren, die es schlecht geformten Programmen ermöglichen, nicht diagnostiziert zu werden, benötigen Sie -pedanticoder -pedantic-errors.
Steve Jessop
56

Dies ist kein undefiniertes Verhalten. Der C-Sprachstandard erfordert eine Diagnose, wenn der sizeofOperator mit einem Funktionsbezeichner (einem Funktionsnamen) verwendet wird, da dies eine Einschränkungsverletzung für den sizeofOperator darstellt.

Als Erweiterung der C-Sprache ermöglicht GCC jedoch die Arithmetik von voidZeigern und Funktionszeigern, indem die Größe einer voidoder einer Funktion als behandelt wird 1. Infolgedessen sizeofbewertet der Bediener 1für voidoder eine Funktion mit GCC. Siehe http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html#Pointer-Arith

Sie können GCC veranlassen, bei Verwendung sizeofmit diesen Operanden eine Warnung auszugeben, indem Sie die Optionen -pedanticoder -Wpointer-arithfür GCC verwenden. Oder machen Sie einen Fehler mit -Werror=pointer-arith.

Michael Burr
quelle
Ihre Logik ist fehlerhaft. C erfordert Diagnosemeldungen für einige, aber nicht alle UB. Sie können nicht angeben, dass etwas Verhalten definiert hat, nur weil es eine Diagnose gibt.
MSalters
4
C erfordert eine Diagnose für alle Einschränkungsverletzungen (5.1.1.3 Diagnose in C99 oder C11). Eine Einschränkung (3.8 in C99 / C11) ist eine "syntaktische oder semantische Einschränkung, nach der die Darstellung von Sprachelementen zu interpretieren ist", die zu sagen scheint, dass etwas, das den Einschränkungen nicht folgt, nicht interpretiert werden kann .
Michael Burr
3
Und um klar zu sein - eine Einschränkungsverletzung führt nicht zu undefiniertem Verhalten. Es ist ein Fehler, wie ein Syntaxfehler. Zum Beispiel sagt der Standard, "wenn eine" soll "oder" soll nicht "Anforderung, die außerhalb einer Einschränkung erscheint, verletzt wird, ist das Verhalten undefiniert". Wenn eine Einschränkungsverletzung zu UB führen würde, warum sollte der Standard dann nur über die "Solls" und "Solls nicht" sprechen, die hier nicht in Einschränkungen enthalten sind?
Michael Burr
3
Ich habe wirklich nicht viel über UB sizeofgesagt, außer dass eine Funktion nicht UB ist (was ich so ziemlich nur erwähnte, weil andere Antworten besagten, dass es UB war). Aber vielleicht habe ich das durcheinander gebracht, weil ich den Satz so strukturiert habe. Um klarer zu sein. sizeofEine Funktion ist nicht UB (wie mehrere Antworten behauptet haben). Es ist eine Einschränkungsverletzung. Daher ist eine Diagnose erforderlich. GCC erlaubt es als Erweiterung.
Michael Burr
2
@KerrekSB: Das OP erhält keine Diagnose, da vermutlich GCC verwendet wird, was diese Verwendung als C-Spracherweiterung ermöglicht.
Michael Burr
13

Dies bedeutet, dass der Compiler-Writer sich für einen Wert von 1 entschieden hat, anstatt Dämonen aus der Nase fliegen zu lassen (tatsächlich war es eine andere undefinierte Verwendung sizeof, die uns diesen Ausdruck gab: "Der C-Compiler selbst MUSS eine Diagnose ausgeben, wenn dies die erste erforderliche ist Eine Diagnose, die sich aus Ihrem Programm ergibt und dann möglicherweise selbst dazu führt, dass Dämonen aus Ihrer Nase fliegen (was übrigens durchaus die dokumentierte Diagnosemeldung sein könnte), genauso wie sie möglicherweise eine weitere Diagnose für weitere Verstöße gegen Syntaxregeln oder -beschränkungen (oder aus irgendeinem Grund, den es wählt). " https://groups.google.com/forum/?fromgroups=#!msg/comp.std.c/ycpVKxTZkgw/S2hHdTbv4d8J

Daraus ergibt sich die umgangssprachliche Bezeichnung "Nasendämonen" für alles, was ein Compiler als Reaktion auf ein undefiniertes Konstrukt tun möchte. 1ist der Nasendämon dieses Compilers für diesen Fall.

Jon Hanna
quelle
@IlmariKaronen Ich muss allerdings zugeben, dass es einen Grund gibt, warum die meisten meiner Antworten zu C (und C ++) entweder auf allgemeinen sprachunabhängigen Prinzipien oder auf solchen historischen Nuggets beruhen. Meine C-Erfahrung grenzt an die Geschichte an sich :)
Jon Hanna
7

Wie andere betonten, kann sizeof () einen beliebigen gültigen Bezeichner annehmen, gibt jedoch kein gültiges (ehrlich wahres und gültiges) Ergebnis für Funktionsnamen zurück. Darüber hinaus kann es definitiv zu einem "Dämonen aus der Nase" -Syndrom führen oder auch nicht.

Wenn Sie die Größe Ihrer Programmfunktion profilieren möchten, überprüfen Sie die Linker-Map, die sich im Verzeichnis der Zwischenergebnisse befindet (das Verzeichnis, in dem die Dinge in .obj / .o kompiliert werden oder in dem das resultierende Image / die ausführbare Datei abgelegt ist). Manchmal gibt es eine Option, um diese Map-Datei zu generieren oder nicht ... sie ist vom Compiler / Linker abhängig.

Wenn Sie die Größe eines Zeigers auf eine Funktion haben möchten, haben sie alle die gleiche Größe, die Größe eines Adressierungsworts auf Ihrer CPU.

jpinto3912
quelle
1
Was für eine Aussage ist "es kann definitiv oder nicht" ??? Gilt das nicht für buchstäblich alles?
Kerrek SB
@KerrekSB ja, aber hier kann es etwas tun oder nicht und kann immer noch innerhalb der Regeln sein. Es ist wahr, dass ein Compiler das Kompilieren ablehnen kann oder nicht, int x = 1;aber nur einer davon ist für einen standardkonformen Compiler zulässig. Wenn sizeof()es auf eine Funktion angewendet wird, kann es einen festgelegten Wert zurückgeben oder nicht oder die Kompilierung verweigern oder einen zufälligen Wert zurückgeben, der auf dem basiert, was sich zu diesem Zeitpunkt in einem bestimmten Register befindet. Buchstäbliche Nasendämonen sind unwahrscheinlich, liegen jedoch im Rahmen des Standards.
Jon Hanna
@kerrek Es kann für nichts wahr sein oder für nichts falsch sein ... betrachte es als unscharf unlogisch.
jpinto3912
1
Wenn Sie die Größe eines Zeigers auf eine Funktion wissen möchten, wenden Sie ihn sizeofauf einen Zeiger auf eine Funktion an.
Alexis