Was ist über die Größe eines Funktionszeigers garantiert?

Lesezeit: 4 Minuten

[*]

In C muss ich die Größe einer Struktur kennen, die Funktionszeiger enthält. Kann ich garantieren, dass auf allen Plattformen und Architekturen:

  • die Größe eines void* ist die gleiche Größe wie ein Funktionszeiger?
  • die Größe des Funktionszeigers unterscheidet sich nicht aufgrund seines Rückgabetyps?
  • die Größe des Funktionszeigers unterscheidet sich nicht aufgrund seiner Parametertypen?

Ich nehme an, dass die Antwort auf alle diese Fragen Ja ist, aber ich möchte sicher sein. Für den Kontext rufe ich an sizeof(struct mystruct) und nichts weiter.

Benutzeravatar von Oliver Charlesworth
Oliver Charlesworth
[*]

Aus C99-Spezifikation, Abschnitt 6.2.5, Absatz 27:

Ein Zeiger auf void muss die gleichen Darstellungs- und Ausrichtungsanforderungen haben wie ein Zeiger auf einen Zeichentyp. In ähnlicher Weise müssen Zeiger auf qualifizierte oder nicht qualifizierte Versionen kompatibler Typen dieselben Darstellungs- und Ausrichtungsanforderungen haben. Alle Zeiger auf Strukturtypen müssen die gleichen Darstellungs- und Ausrichtungsanforderungen haben. Alle Zeiger auf Union-Typen müssen untereinander die gleichen Darstellungs- und Ausrichtungsanforderungen haben. Zeiger auf andere Typen müssen nicht die gleichen Darstellungs- oder Ausrichtungsanforderungen haben.

Also nein; keine Garantie, dass a void * kann einen Funktionszeiger enthalten.

Und Abschnitt 6.3.2.3, Absatz 8:

Ein Zeiger auf eine Funktion eines Typs kann in einen Zeiger auf eine Funktion eines anderen Typs umgewandelt werden und wieder zurück; das Ergebnis soll mit dem ursprünglichen Zeiger verglichen werden.

was impliziert, dass ein Funktionszeigertyp jeden anderen Funktionszeigerwert enthalten kann. Technisch gesehen ist das nicht dasselbe wie zu garantieren, dass die Größe von Funktionszeigertypen nicht variieren kann, sondern lediglich, dass ihre Werte den gleichen Bereich einnehmen.

Benutzeravatar von Steve Jessop
Steve Jessop
[*]

Nein nein Nein.

C bevorzugt keine Harvard-Architekturen mit unterschiedlichen Code- und Datenzeigergrößen, da Sie beim Programmieren für eine solche Architektur idealerweise Daten im Programmspeicher speichern möchten (String-Literale und dergleichen), und dazu benötigen Sie Objektzeiger der Coderaum. Aber es verbietet es ihnen nicht, so dass Funktionszeiger laut Standard auf einen Adressraum verweisen können, der eine andere Größe als der Datenadressraum hat.

Allerdings kann jeder Funktionszeiger in einen anderen Funktionszeigertyp umgewandelt werden[*] und zurück, ohne den Wert zu löschen, auf die gleiche Weise, auf die jeder Objektzeiger umgewandelt werden kann void* und zurück. Daher wäre es ziemlich überraschend, wenn Funktionszeiger je nach Signatur in der Größe variieren würden. Es gibt keinen offensichtlichen “Nutzen” für den zusätzlichen Speicherplatz, wenn Sie in der Lage sein müssen, den gleichen Wert irgendwie auf weniger Speicherplatz zu speichern und ihn dann beim Zurückwerfen abzurufen.

[*] Danke, Schot.

  • Allgemeiner: Jeder Funktionszeiger kann in jeden anderen Funktionszeigertyp und zurück konvertiert werden. (C99 6.3.2.3/8)

    – schott

    15. Oktober 2010 um 11:38 Uhr


  • @schot: Richtig, in diesem Fall wäre es wirklich pervers, sie unterschiedlich groß zu machen, da alle Funktionszeigertypen unabhängig von der Größe genau denselben Satz von Werten darstellen müssen. Nämlich die Adresse jeder Funktion plus einen Nullzeiger.

    – Steve Jessop

    15. Oktober 2010 um 11:41 Uhr

  • Ausgezeichnete Antwort. Meine Frage von neulich veranschaulicht mögliche Fallstricke hier: stackoverflow.com/questions/3889541/…

    – Vicky

    15. Oktober 2010 um 11:42 Uhr

  • “C unterstützt Harvard-Architekturen nicht wirklich”; Ich denke, das ist ein roter Hering. Es gibt viele solcher Architekturen, die C unterstützen!

    – Oliver Charlesworth

    15. Oktober 2010 um 11:45 Uhr

  • @Oli: Sicher, Sie können Sachen in den Datenraum kopieren, aber dann haben Sie (a), aber nicht (b). Sie belegen wertvollen Speicher, was eine programmierergesteuerte Optimierung motiviert. Mit “hässlichem Hack” meine ich nongnu.org/avr-libc/user-manual/pgmspace.html. Sie können dann keinen echten “Objekt”-Zeiger erhalten, auf den zB das Programm selbst übergehen könnte memcpy, weil memcpy nicht weiß, wie man es dereferenziert. Um das zu erreichen, müssten Sie aufgeben und einfach die Größe der Objektzeiger erhöhen, was wiederum wertvollen Speicher kostet und wahrscheinlich bei jedem Speicherzugriff einen Laufzeitwechsel erfordert!

    – Steve Jessop

    15. Oktober 2010 um 12:08 Uhr


[*]

Zusätzlich zu den anderen Antworten sagt Wikipedia Folgendes:

http://en.wikipedia.org/wiki/Function_pointer

Obwohl Funktionszeiger in C und C++ als einfache Adressen implementiert werden können, ist dies normalerweise der Fall
sizeof(Fx)==sizeof(void *)werden Member-Zeiger in C++ oft als “fette Zeiger” implementiert, typischerweise zwei- oder dreimal so groß wie ein einfacher Funktionszeiger, um mit virtueller Vererbung umzugehen.

Ein Funktionszeiger ist eine Abstraktion. Solange die Anforderungen der Norm erfüllt sind, ist alles möglich. Dh wenn Sie weniger als 256 Funktionen in Ihrem Programm haben, könnten Funktionszeiger implementiert werden, indem Sie ein einzelnes Byte mit dem Wert 0 für NULL und den Werten 1 bis 255 als Index in eine Tabelle mit den physikalischen Adressen verwenden. Wenn Sie 255 Funktionen überschreiten, könnte es erweitert werden, um 2 Bytes zu verwenden.

  • Ich verstehe nicht, wie das falsch sein soll. Dies ist wirklich eine Möglichkeit für eine legale C-Implementierung, obwohl ich überrascht wäre, wenn es eine Implementierung gäbe, die dies tut.

    – Nategans

    15. Oktober 2010 um 13:17 Uhr

  • War nicht meine Ablehnung, aber das C++ Member Pointer-Zeug ist irrelevant, da sich die Frage um C dreht. Der letzte Absatz ist jedoch ein absolut guter Punkt, Funktionszeiger sicherlich könnte legal ein Index in eine Tabelle sein, mit einer zusätzlichen Indirektionsebene, um sie tatsächlich aufzurufen.

    – Steve Jessop

    22. Februar 2011 um 10:31 Uhr


[*]

Es gibt ein praktisches Beispiel für unterschiedliche Größen, die früher üblich waren. In der MS-DOS- und frühen Windows C-Programmierung hatten Sie im “mittleren” Speichermodell 16-Bit-Datenzeiger, aber 32-Bit-Funktionszeiger, und das “kompakte” Speichermodell war umgekehrt.

1389670cookie-checkWas ist über die Größe eines Funktionszeigers garantiert?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy