C空结构 – 这是什么意思/做什么?

我在一个需要使用的设备的头文件中find了这个代码,尽pipe我已经做了C多年,但我从来没有遇到过这样的情况:

struct device { }; struct spi_device { struct device dev; }; 

它用在:

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

也在这里:

 struct spi_device *spi = phy->spi; 

在哪里定义相同。

我不确定这个定义有什么意义。 它是在一个Linux的应用程序的头文件,但令人困惑的使用它。 任何解释,想法? 任何人以前见过这个(我相信你们有一些:)。

谢谢! :BP:

这不是C,因为C结构必须包含至less一个命名成员:

(C11,6.7.2.1结构和联合说明符p8)“如果struct-declaration-list不包含任何指定的成员,直接或通过匿名结构或匿名联合,行为是未定义的。

但是一个GNU C扩展:

GCC允许C结构没有成员:

 struct empty { }; 

该结构的大小为零

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

我不知道你的例子中这个构造的目的是什么,但总的来说,我认为它可以用作结构types的前向声明。 请注意,在C ++中允许有一个没有成员的类。

在Linux 2.4中,有一个在Linux内核2.4(在include / linux / spinlock.h中)定义spin_lock_ttypes别名时使用条件编译的空结构types的例子:

 #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 

如果DEBUG_SPINLOCKS < 1不必更改函数API就可以节省一些空间。 它还允许定义spinlock_ttypes的虚拟(零)大小的对象。

在include / linux / device.h中的条件编译中使用的空结构hack(最近的)Linux内核中的另一个例子:

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

请参阅与Greg Kroah-Hartman讨论最后一个例子:

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

这不是标准C.
C11:6.2.5-20:

– 结构types描述了一个顺序分配的非空集成员对象(在某些情况下,一个不完整的数组),每个成员对象都有一个可选的指定名称和可能的不同types。

J.2未定义的行为:

在以下情况下行为是不确定的:
….
结构或联合的定义没有任何指定的成员 (包括通过匿名结构和联盟间接指定的成员 )(6.7.2.1)。

海湾合作委员会使用它作为一个扩展 (没有更详细的时间/应该在哪里使用它)。 在任何程序中使用它都会使其具有特定的编译器。

对于一个库来说,这样做的一个原因是库开发人员不希望你知道或干扰这些结构的内部。 在这些情况下,他们可能会提供结构spi_device/device的“接口”版本(这是您可能会看到的),并具有第二个types定义,用于定义库中实际成员使用的另一个版本的结构。

既然你不能访问结构成员,或者甚至用这种方法自己创build那个types的兼容结构(因为即使你的编译器不知道这个结构的大小实际大小),这只有在库本身创build结构时才有效,指针,并不需要你修改任何成员。

如果你添加一个空的结构体作为另一个结构体的第一个成员,那么空的结构体可以作为一个“标记接口”,也就是说当你将一个指向外部结构体的指针转换为内部结构体的指针并且转换成功时,外部结构是“标记”的东西。

也可能只是一个未来发展的地方持有人,不确定。 希望这可以帮助

这是有效的C

 struct empty; struct empty *empty; 

并且便于使用存储器的不透明区域的地址。

这些地址通常从库子程序获得并传递给库子程序。

例如,像这样的东西是在stdio.h中完成的

我知道这是一个古老的线程,我不想绕过necro-bumping,但是我已经在链表里面做了空白结构的实验,我觉得我的研究值得一提,因为这个线程与什么空白的结构可能意味着/做。

空白结构在GCC下使用是很好的。 从我发现,只要你malloc你的指针结构,那么你将确实分配适当的空间指针结构内的指针。 即使它是空白的typedef,即没有成员,你仍然在结构中声明一个指针variables。 如果你NULL宣布他们然后没有任何工作。

真的,尽pipe如此,所有这一切都值得,你也可以使用一个正常的链表。 这真的没什么特别的,只是一点点的代码,我忍不住写了。

代码如下:

 /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: main.c * Author: access * * Created on October 2, 2016, 11:23 PM */ #include <stdio.h> #include <stdlib.h> typedef struct { } blankptr; typedef struct { struct blankptr *blankptr; struct node *dataptr; } ptrstruct; typedef struct { int val; float x; float y; char test; } node; /* * */ int main(int argc, char** argv) { ptrstruct *ptr0 = malloc(sizeof(*ptr0)); ptrstruct *ptr1 = malloc(sizeof(*ptr1)); ptrstruct *ptr2 = malloc(sizeof(*ptr2)); ptrstruct *ptr3 = malloc(sizeof(*ptr3)); node *data0 = malloc(sizeof(*data0)); node *data1 = malloc(sizeof(*data1)); node *data2 = malloc(sizeof(*data2)); node *data3 = malloc(sizeof(*data3)); ptr0->blankptr = ptr1; ptr0->dataptr = data1; printf("ptr0->blankptr = %p \n", ptr0->blankptr); printf("ptr0->dataptr = %p \n", ptr0->dataptr); ptr1->blankptr = ptr2; ptr1->dataptr = data2; printf("ptr1->blankptr = %p \n", ptr1->blankptr); printf("ptr1->dataptr = %p \n", ptr1->dataptr); ptr2->blankptr = ptr3; ptr2->dataptr = data3; printf("ptr2->blankptr = %p \n", ptr2->blankptr); printf("ptr2->dataptr = %p \n", ptr2->dataptr); return (EXIT_SUCCESS); }