【问题标题】:Use of redefining void pointer to pointer to an anonymous structure?使用重新定义指向匿名结构的指针的 void 指针?
【发布时间】:2017-04-29 14:42:29
【问题描述】:

我正在使用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 * 重新定义为指向匿名结构的指针的逻辑。 “奇怪的破坏企图”暗示了什么样的黑客行为?

【问题讨论】:

  • 有趣的细节也是#include 周围的#define#undef。它会建议标头使用#define 而不是typedef,这可能暗示代码中还有其他WTF。这可以解释评论的被动攻击语气......

标签: c uefi


【解决方案1】:

库在 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;

将收获随之而来的“不兼容的指针类型”编译时错误。

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

【讨论】:

  • 它甚至可以反复踢你,这取决于你的编译器设置
  • @StoryTeller Javascript 也有这个功能。 softwareengineering.stackexchange.com/a/11812/168891
  • 我不确定我是否理解正确。如果这样做,可以 *EFI_HANDLE 现在指向什么类型?
  • @JustinLardinois 它指向一个结构。这是一个众所周知的概念,称为句柄范例!这一切都是出于两个原因 - 类型安全(编译时验证)和抽象(如在 OOP 中将内部与接口分离);
  • @Alex 我当时是否理解指向​​未命名的struct 类型的指针可以指向任何struct 类型?我尝试在谷歌上搜索“c 句柄范例”,但没有找到关于具有该名称的概念的任何结果。
【解决方案2】:

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

匿名结构只能作为另一个结构的成员存在,
它也不能有标签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)
类型说明符是没有标记的结构说明符的未命名成员称为 匿名结构;一个未命名的成员,其类型说明符是一个联合说明符 没有标签称为匿名联合。匿名结构或联合的成员 被认为是包含结构或联合的成员。这适用 如果包含结构或联合也是匿名的,则递归

【讨论】:

  • 值得一提的是,在旧版本的 C 标准中,“匿名结构”并不作为一个单独的术语存在。对于那些版本,“匿名”将被解释为普通的英文单词,意思是“没有名字”,对于结构类型来说,它似乎完全可以解释为“没有标签”。
猜你喜欢
  • 2016-03-21
  • 1970-01-01
  • 2014-10-01
  • 1970-01-01
  • 2015-01-04
  • 1970-01-01
  • 1970-01-01
  • 2018-11-03
相关资源
最近更新 更多