使用将 void 指针重新定义为指向匿名结构的指针?
Use of redefining void pointer to pointer to an anonymous structure?
我正在处理 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 *
重新定义为指向匿名结构的指针的逻辑。 "bizzare sabotage attempt" 暗示了什么样的 hack?
库正在对 EFI_HANDLE 中保存的地址后面的内部数据对象使用 信息隐藏。但在这样做时,他们使代码 更多 容易受到意外错误的影响。
在 C 中,void*
被透明地转换为 any 其他非 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;
将收获随后的 "incompatible pointer type" 编译时错误。
最后,作为一个匿名结构,没有无意义的结构标签名称添加到您可以使用(意外或恶意)的已经污染的名称 space。
这不是匿名结构,而是没有标签的结构。
匿名结构只能作为另一个结构的成员存在,
而且它也不能有标签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)
类型说明符是不带标记的结构说明符的未命名成员称为
匿名结构;一个未命名的成员,其类型说明符是一个联合说明符
没有标签称为匿名联合。匿名结构或联合的成员
被认为是包含结构或联合的成员。这适用
如果包含的结构或联合也是匿名的,则递归
我正在处理 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 *
重新定义为指向匿名结构的指针的逻辑。 "bizzare sabotage attempt" 暗示了什么样的 hack?
库正在对 EFI_HANDLE 中保存的地址后面的内部数据对象使用 信息隐藏。但在这样做时,他们使代码 更多 容易受到意外错误的影响。
在 C 中,void*
被透明地转换为 any 其他非 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;
将收获随后的 "incompatible pointer type" 编译时错误。
最后,作为一个匿名结构,没有无意义的结构标签名称添加到您可以使用(意外或恶意)的已经污染的名称 space。
这不是匿名结构,而是没有标签的结构。
匿名结构只能作为另一个结构的成员存在,
而且它也不能有标签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)
类型说明符是不带标记的结构说明符的未命名成员称为
匿名结构;一个未命名的成员,其类型说明符是一个联合说明符
没有标签称为匿名联合。匿名结构或联合的成员
被认为是包含结构或联合的成员。这适用
如果包含的结构或联合也是匿名的,则递归