【问题标题】:Is this typedef-ing a function in C++?这个 typedef 是 C++ 中的一个函数吗?
【发布时间】:2015-10-31 18:07:24
【问题描述】:

这是一个示例 C++ 代码块。我阅读了 typedef、struct、enum 和 union 的定义,但仍然无法解读。

typedef NTSTATUS (WINAPI * PFN_NTQUERYINFORMATIONFILE)(
    IN HANDLE FileHandle,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    OUT PVOID FileInformation,
    IN ULONG Length,
    IN FILE_INFORMATION_CLASS FileInformationClass
);
  1. NTSTATUS (WINAPI * PFN_NTQUERYINFORMATIONFILE) 是一个函数吗?为什么参数的意思是中间有一个 *?
  2. IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock.. IN/OUT 是什么意思?
  3. 为什么没有新别名?
  4. 我可以声明一个新的别名和一个指针别名吗?在下面的示例中,我会使用 PFILE_NAME_INFORMATION 作为指针名称,否则使用 FILE_NAME_INFORMATION 吗?

    typedef struct _FILE_NAME_INFORMATION { ... } 
    FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
    

【问题讨论】:

  • 额外的空格,宏,...你有 IDE 吗?
  • 首先让我说_FILE_NAME_INFORMATION是一个保留标识符:你不能合法使用它。其次,INOUT 不是 C++ 关键字,所以我猜测它们只是 #defines 什么都没有,仅用作注释。
  • 在你的最后一个问题 4. 中,你真的是在问 structs 还是这只是一个类比,而你实际上是在问函数指针?

标签: c++ struct alias typedef


【解决方案1】:

这个 typedef 声明

typedef NTSTATUS (WINAPI * PFN_NTQUERYINFORMATIONFILE)(
    IN HANDLE FileHandle,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    OUT PVOID FileInformation,
    IN ULONG Length,
    IN FILE_INFORMATION_CLASS FileInformationClass
);

为该类型引入alias namedPFN_NTQUERYINFORMATIONFILE`

NTSTATUS (WINAPI * )(
    IN HANDLE FileHandle,
    OUT PIO_STATUS_BLOCK IoStatusBlock,
    OUT PVOID FileInformation,
    IN ULONG Length,
    IN FILE_INFORMATION_CLASS FileInformationClass
);

表示一个指向函数的指针,有 5 个参数,返回类型为NTSTATUS

现在你可以使用这个名字来声明指向这种类型函数的指针

PFN_NTQUERYINFORMATIONFILE ptr;

您可以通过以下方式获得相同的效果,看起来更清晰

using PFN_NTQUERYINFORMATIONFILE =  
    NTSTATUS (WINAPI * )(
        IN HANDLE FileHandle,
        OUT PIO_STATUS_BLOCK IoStatusBlock,
        OUT PVOID FileInformation,
        IN ULONG Length,
        IN FILE_INFORMATION_CLASS FileInformationClass
    );

同时考虑下面这个简单的例子

#include <iostream>

int sum( int x, int y )
{
    return x + y;
}

int product( int x, int y )
{
    return x * y;
}

int division( int x, int y )
{
    return x / y;
}

typedef int ( *fp )( int, int );

int main( )
{
    for ( fp f : { sum, product, division } ) std::cout << f( 10, 2 ) << std::endl;
}

输出是

12
20
5

考虑到函数名在表达式中使用时会隐式转换为指向函数的指针。

因此,例如上面演示程序中的函数的这条语句是有效的

std::cout << ( ***/* replace the comment with as many asterisks as you like */****sum )( 10, 20 ) << std::endl;

因此,如果您根据程序中输入符号的数量获得报酬,那么您可以在函数调用中使用此技巧。

(****************************************************sum )( 10, 20 );

这仅受编译器限制。

至于INOUT 那么它们是微软用来明确函数的每个参数的用途的宏,是提供输入值还是用作输出参数。

【讨论】:

    【解决方案2】:

    这是函数指针的类型别名。

    NTSTATUS (WINAPI * PFN_NTQUERYINFORMATIONFILE) 是一个函数吗?为什么参数的意思是中间有一个*?

    不,这只是类型的一部分。 * 表示一个指针。这是一个指向函数的指针,该函数具有 WINAPI (__stdcall) 调用约定、NTSTATUS 返回值和多个参数(HANDLEPIO_STATUS_BLOCKPVOIDULONG 和 @987654329 @)。

    IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock.. IN/OUT 是什么意思?

    这些是注释。 IN 表示该函数仅将参数用于输入,OUT 表示该函数仅将参数用于输出(它写入参数指向的内容)。 INOUT 意味着函数读取和写入指向的内容。

    Neil MacIntosh 实际上在今年的 CppCon 上做了几个关于静态分析的演讲,他谈到了这些注释是如何出现在 Microsoft 代码库中的,以及它们如何帮助改进静态分析工具的功能而不需要更多资源。但是,您可以为实际类型提供相同的帮助,而不是编译成空的注释,这就是带有 GSL 的 CppCoreGuidelines 项目所采用的方法。

    为什么没有新别名?

    有。这是PFN_NTQUERYINFORMATIONFILE。这只是 C 声明语法的一个怪癖,在大多数情况下,它是从内向外读取,而不是从左到右。

    我可以声明一个新的别名和一个指针别名吗?

    据我所知,没有。如果你对 typedef NTSTATUS(WINAPI func)(...), *func_pointer; 做了同样的把戏,func_pointer 将是 NTSTATUS*func 与问题中的相同,但不是指针。

    这当然适用于通过typedef 生成的其他类型别名,例如问题中的struct 示例,它确实将FILE_NAME_INFORMATION 声明为struct _FILE_NAME_INFORMATIONPFILE_NAME_INFORMATION 作为struct _FILE_NAME_INFORMATION*struct 用于强调所声明的不同类型的名称。

    【讨论】:

      【解决方案3】:
      1. 不,它是一个函数指针。中间的星号只是函数指针正常语法的一部分——WINAPIis just a macro

      2. 宏也是。 IN 表示函数读取的参数(如 const 引用或按值复制的参数),而 OUT 表示用于“返回”参数的参数(如非 const 引用)。

      3. 有一个:PFN_NTQUERYINFORMATIONFILE

      4. Yes.

      【讨论】:

      • 我认为这不是 OP 对 #4 的要求。我认为问题是是否有一种方法可以在单个语句中同时声明函数类型的别名和指向同一函数类型的指针的别名,就像使用其他类型别名(例如结构)一样。跨度>
      • @chris 所以你的意思是这只是一个类比?可能是,但我没有看到任何暗示。 “在下面的示例中 [...]”让我信服。
      • 这是我对这个问题的解释。 OP当然可以澄清。
      猜你喜欢
      • 1970-01-01
      • 2012-09-11
      • 1970-01-01
      • 1970-01-01
      • 2011-11-22
      • 2016-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多