Verwendung der Neudefinition des void-Zeigers, um auf eine anonyme Struktur zu verweisen?

Lesezeit: 4 Minuten

Benutzer-Avatar
Achora

Ich arbeitete mit UEFI treiberbezogener Code, und ich bin auf Folgendes gestoßen:

/* EFI headers define EFI_HANDLE as a void pointer, which renders type
* checking somewhat useless. Work around this bizarre sabotage
* attempt by redefining EFI_HANDLE as a pointer to an anonymous
* structure.
*/
#define EFI_HANDLE STUPID_EFI_HANDLE
#include <ipxe/efi/Uefi/UefiBaseType.h>
#undef EFI_HANDLE
typedef struct {} *EFI_HANDLE;

Der vollständige Quellcode befindet sich in diesem Pfad
http://dox.ipxe.org/include_2ipxe_2efi_2efi_8h_source.html

Dies ist meine erste Begegnung mit einer anonymen Struktur, und ich konnte die Logik der Neudefinition von a nicht erkennen void * auf einen Zeiger auf eine anonyme Struktur. Auf was für einen Hack deutet der „skurrile Sabotageversuch“ hin?

  • Interessantes Detail ist auch die #define und #undef um #include. Es würde vorschlagen, dass Header verwendet #define Anstatt von typedef, was darauf hindeuten könnte, dass der Code auch andere WTFs enthält. Das könnte den passiv-aggressiven Ton des Kommentars erklären…

    – Benutzer694733

    14. Dezember 2016 um 10:20 Uhr

Benutzer-Avatar
WhozCraig

Die Bibliothek verwendet Informationen verstecken auf dem internen Datenobjekt hinter der Adresse, die in einem EFI_HANDLE gehalten wird. Aber dabei machen sie den Code mehr anfällig für versehentliche Fehler.

In C, void* wird transparent zu gegossen irgendein andere nicht-void* nicht konstanter Datenzeigertyp ohne Warnung (es ist durch Sprachdesign).

Die Verwendung eines Nicht-Void-Zeigertyps stellt sicher, dass ein EFI_HANDLE wird nur wo verwendet EFI_HANDLE gehört. Die Typüberprüfung des Compilers tritt Ihnen in die Leiste, wenn Sie sie an einer anderen Stelle übergeben, an der dies nicht der Fall ist EFI_HANDLE sondern ein Hinweis auf etwas anderes.

Bsp.: Als void*wird dies ohne Warnung oder Fehler kompiliert

#include <string.h>

#define EFI_HANDLE void*

int main()
{
    EFI_HANDLE handle = NULL;

    strcpy(handle, "Something");
}

Ändern des Alias ​​zu:

typedef struct {} *EFI_HANDLE;

wird den folgenden Kompilierungsfehler “inkompatibler Zeigertyp” ernten.

Schließlich gibt es als anonyme Struktur keinen sinnlosen Struktur-Tag-Namen, der dem bereits verschmutzten Namensraum hinzugefügt wird, den Sie verwenden können (versehentlich oder ruchlos).

  • Abhängig von Ihren Compiler-Einstellungen kann es Sie sogar wiederholt treten

    – StoryTeller – Unslander Monica

    14. Dezember 2016 um 10:14 Uhr


  • @StoryTeller Javascript hat diese Funktion ebenfalls. softwareengineering.stackexchange.com/a/11812/168891

    – Benutzer2752467

    14. Dezember 2016 um 17:57 Uhr

  • Ich bin mir nicht sicher, ob ich das richtig verstehe. Wenn Sie dies tun, welche Typen kann *EFI_HANDLE jetzt zeigen?

    – Benutzer2752467

    14. Dezember 2016 um 17:59 Uhr


  • @JustinLardinois Es zeigt auf eine Struktur. Es ist ein sehr bekanntes Konzept namens Handle Paradigma! Das alles geschieht aus zwei Gründen: Typsicherheit (Verifizierung zur Kompilierzeit) und Abstraktion (wie in OOP, um Interna von der Schnittstelle zu trennen);

    – Alex D

    14. Dezember 2016 um 18:04 Uhr

  • @Alex Verstehe ich dann richtig, dass ein Zeiger auf einen unbenannten struct Typ kann auf beliebige zeigen struct Typ? Ich habe versucht, “c handle paradigm” zu googeln, habe aber keine Ergebnisse zu einem Konzept mit diesem Namen gefunden.

    – Benutzer2752467

    15. Dezember 2016 um 0:00 Uhr

Benutzer-Avatar
2501

Das ist keine anonyme Struktur, sondern eine Struktur ohne Tag.

Eine anonyme Struktur kann nur als Mitglied einer anderen Struktur existieren,
und es darf auch kein Tag haben1.

Das Definieren einer Struktur ohne Mitglieder ist nicht zulässig. Der Code, den Sie sich ansehen, verwendet eine Compiler-Erweiterung, die dies zulässt.

Die Bibliothek tut dies, um die Definition der Struktur vor dem Benutzer zu verbergen, während die Typsicherheit aufrechterhalten wird.

Es gibt jedoch einen viel besseren Weg, dies zu tun. Wenn Sie eine versteckte Strukturdefinition haben, können Sie trotzdem einen undurchsichtigen Zeiger darauf definieren, der einen Typ hat, also typsicher ist:

struct hidden    //defined in a file and not exposed
{
    int a;
};

void Hidden( struct hidden* );
void Other( struct other* );
struct hidden* a = NULL;    //doesn't see the definition of struct hidden
Hidden( a );    //it may be used 
Other( a );    //compiler error

1 (Zitiert aus: ISO/IEC 9899:201x 6.7.2.1 Structure and union specifiers 13)
Ein unbenanntes Element, dessen Typbezeichner ein Strukturbezeichner ohne Tag ist, wird als anonyme Struktur bezeichnet; Ein unbenannter Member, dessen Typbezeichner ein Union-Bezeichner ohne Tag ist, wird als anonyme Union bezeichnet. Die Mitglieder einer anonymen Struktur oder Vereinigung werden als Mitglieder der enthaltenden Struktur oder Vereinigung betrachtet. Dies gilt rekursiv, wenn die enthaltende Struktur oder Union ebenfalls anonym ist

  • Erwähnenswert ist, dass in älteren Versionen des C-Standards „anonyme Struktur“ nicht als eigenständiger Begriff existierte. Für diese Versionen würde “anonymous” einfach als das gewöhnliche englische Wort interpretiert werden, das “ohne Name” bedeutet, was für Strukturtypen durchaus als “ohne Tag” zu interpretieren scheint.

    Benutzer743382

    14. Dezember 2016 um 15:21 Uhr

1116360cookie-checkVerwendung der Neudefinition des void-Zeigers, um auf eine anonyme Struktur zu verweisen?

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

Privacy policy