使用重定义void指针指向匿名结构的指针?

时间:2016-12-14 10:01:56

标签: c uefi

我正在处理与UEFI驱动程序相关的代码,我遇到了这个问题:

/* 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;

完整的源代码在此路径中 http://dox.ipxe.org/include_2ipxe_2efi_2efi_8h_source.html

这是我第一次遇到匿名结构,我无法弄清楚将void *重新定义为指向匿名结构的指针的逻辑。 “古怪的破坏尝试”暗示了什么样的黑客?

2 个答案:

答案 0 :(得分:19)

该库在EFI_HANDLE中保存的地址后面的内部数据对象上使用信息隐藏。但在这样做的过程中,他们会使代码更多容易受到意外错误的影响。

在C中,void*透明地转换为任何其他非void*非常量数据指针类型而不发出警告(它&#39 ; s语言设计)。

使用非void指针类型可确保EFI_HANDLE仅用于EFI_HANDLE所属的位置。当你把它传递到不是EFI_HANDLE的其他地方时,编译器的类型检查会在你的腹股沟中踢你,而不是指向别的东西。

例如:void*,这将编译时没有警告或错误

#include <string.h>

#define EFI_HANDLE void*

int main()
{
    EFI_HANDLE handle = NULL;

    strcpy(handle, "Something");
}

将别名更改为:

typedef struct {} *EFI_HANDLE;

将获得随后的&#34;不兼容的指针类型&#34;编译时错误。

最后,作为一个匿名结构,没有任何毫无意义的结构标记名称可以添加到您可以使用的已经污染的名称空间中(无意或者是邪恶的)。

答案 1 :(得分:7)

这不是一个匿名结构,而是一个没有标签的结构。

匿名结构只能作为另一个结构的成员存在,
它也必须没有标签 1

不允许定义不带任何成员的结构。您正在查看的代码是使用允许此操作的编译器扩展。

库正在执行此操作以隐藏用户的结构定义,同时保持类型安全。

然而,有一个更好的方法来做到这一点。如果你有一个隐藏的结构定义,你仍然可以定义一个指向它的不透明指针,它有一个类型,所以它是类型安全的:

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 (引自:ISO / IEC 9899:201x 6.7.2.1结构和联合说明符13)
类型说明符是没有标记的结构说明符的未命名成员称为 匿名结构;一个未命名的成员,其类型说明符是一个联合说明符 没有标签被称为匿名联盟。匿名结构或联合的成员 被认为是包含结构或联合的成员。这适用 如果包含的结构或联合也是匿名的

,则递归地递归