wake-up-neo.com

C leere Struktur - was bedeutet/tun das?

Ich habe diesen Code in einer Header-Datei für ein Gerät gefunden, das ich verwenden muss, und obwohl ich schon seit Jahren mit C gearbeitet habe, habe ich noch Folgendes festgestellt:

struct device {
};

struct spi_device {
    struct device dev;
};

und es verwendet wie in:

int spi_write_then_read(struct spi_device *spi, 
const unsigned char *txbuf, unsigned n_tx,
unsigned char *rxbuf, unsigned n_rx);

und auch hier:

struct spi_device *spi = phy->spi;

wo es gleich definiert ist.

Ich bin mir nicht sicher, worum es bei dieser Definition geht. Es befindet sich in einer Header-Datei für eine Linux-Anwendung der Platine, ist aber durch die Verwendung verwirrt. Irgendwelche Erklärungen, Ideen? Jeder hat das schon mal gesehen (ich bin mir sicher, einige von euch haben :).

Danke! : bp:

46
Billy Pilgrim

Dies ist kein C, da C-Strukturen mindestens ein benanntes Member enthalten müssen:

(C11, 6.7.2.1 Struktur- und Union-Spezifizierer, Seite 8) "Wenn die Struktur-Deklarationsliste weder direkt noch über eine anonyme Struktur oder anonyme Union benannte Mitglieder enthält, ist das Verhalten undefiniert."

aber eine GNU C-Erweiterung:

GCC erlaubt einer C-Struktur, keine Mitglieder zu haben:

struct empty {
};

Die Struktur hat die Größe Null

https://gcc.gnu.org/onlinedocs/gcc/Empty-Structures.html

Ich weiß nicht, was der Zweck dieses Konstrukts in Ihrem Beispiel ist, aber im Allgemeinen denke ich, dass es als Vorwärtsdeklaration des Strukturtyps verwendet werden kann. Beachten Sie, dass in C++ eine Klasse ohne Member zulässig ist. 

In Linux 2.4 gibt es ein Beispiel für einen leeren Strukturtyp mit bedingter Kompilierung in der Definition des spin_lock_t-Typenalias im Linux-Kernel 2.4 (in include/linux/spinlock.h):

#if (DEBUG_SPINLOCKS < 1)

/* ... */

typedef struct { } spinlock_t;

#Elif (DEBUG_SPINLOCKS < 2)

/* ... */

typedef struct {
    volatile unsigned long lock;
} spinlock_t;

#else /* (DEBUG_SPINLOCKS >= 2) */

/* ... */

typedef struct {
    volatile unsigned long lock;
    volatile unsigned int babble;
    const char *module;
} spinlock_t;

#endif

Der Zweck besteht darin, etwas Platz zu sparen, ohne die Funktions-API für den Fall DEBUG_SPINLOCKS < 1 ändern zu müssen. Außerdem können Sie Dummy-Objekte (mit der Größe null) vom Typ spinlock_t definieren.

Ein weiteres Beispiel im (aktuellen) Linux-Kernel eines leeren Strukturhacks, der mit der bedingten Kompilierung in include/linux/device.h verwendet wird:

struct acpi_dev_node {
#ifdef CONFIG_ACPI
    void *handle;
#endif
};

Das letzte Beispiel finden Sie hier in der Diskussion mit Greg Kroah-Hartman:

https://lkml.org/lkml/2012/11/19/453

40
ouah

Dies ist kein Standard C.
C11: 6.2.5-20:

- Ein Strukturtyp beschreibt eine sequentiell zugewiesene nicht leere Gruppe von member - Objekten (und unter bestimmten Umständen ein unvollständiges Array), von denen jedes einen optional angegebenen Namen und möglicherweise einen unterschiedlichen Typ hat. 

J.2 Undefiniertes Verhalten:

Das Verhalten ist unter folgenden Umständen undefiniert:
....
- Eine Struktur oder Vereinigung wird ohne benannte Mitglieder definiert (einschließlich derjenigen, die indirekt über anonyme Strukturen und Vereinigungen angegeben wurden) (6.7.2.1). 

GCC verwendet es als Erweiterung (es wird dort nicht genauer angegeben, wann/wo es verwendet werden sollte). Wenn Sie dies in einem beliebigen Programm verwenden, wird der Compiler spezifisch.

22
haccks

Ein Grund dafür könnte für eine Bibliothek sein, dass die Bibliotheksentwickler nicht möchten, dass Sie die Interna dieser Struktur kennen oder stören. In diesen Fällen können sie eine "Schnittstellen" -Version der Strukturen spi_device/device bereitstellen (was Sie möglicherweise sehen werden) und über eine zweite Typdefinition verfügen, die eine andere Version dieser Strukturen für die Verwendung in der Bibliothek mit den tatsächlichen Mitgliedern definiert.

Da Sie mit diesem Ansatz nicht selbst auf Strukturelemente zugreifen oder kompatible Strukturen dieses Typs erstellen können (da selbst Ihr Compiler die tatsächliche Größe dieser Struktur nicht kennen würde), funktioniert dies nur, wenn die Bibliothek die Strukturen selbst erstellt und nur Sie übergibt Verweise darauf, und Sie brauchen keine Mitglieder zu ändern.

3
Dreamer

Wenn Sie eine leere Struktur als erstes Mitglied einer anderen Struktur hinzufügen, kann die leere Struktur als "Marker-Schnittstelle" dienen, dh wenn Sie einen Zeiger auf diese äußere Struktur in einen äußeren Zeiger der inneren Struktur und die Besetzung gelingt, wissen Sie, dass die äußere Struktur als etwas "markiert" ist.

Es könnte auch nur ein Platzhalter für die zukünftige Entwicklung sein, nicht sicher. Hoffe das hilft

2

Dies ist gültig C

struct empty;
struct empty *empty;

und erleichtert die Verwendung von Adressen von undurchsichtigen Speicherbereichen.

Solche Adressen werden normalerweise von Bibliotheksunterprogrammen erhalten und an diese weitergegeben.

Zum Beispiel wird so etwas in stdio.h gemacht

0
J M D