这是 C++ 中的函数类型定义吗?

Is this typedef-ing a function in C++?

本文关键字:定义 类型 函数 C++ 这是      更新时间:2023-10-16

这是一个示例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. 在 HANDLE FileHandle 中,OUT PIO_STATUS_BLOCK IoStatusBlock..输入/输出是什么意思?
  3. 为什么没有新的别名?
  4. 是否可以声明新的别名和指针别名?在下面的示例中,我会使用 PFILE_NAME_INFORMATION 作为指针名称,否则FILE_NAME_INFORMATION?

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

这个 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 named PFN_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,那么它们是Microsoft使用的宏,用于明确函数的每个参数的用途,是提供输入值还是用作输出参数。

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

NTSTATUS (WINAPI * PFN_NTQUERYINFORMATIONFILE( 是一个函数吗?为什么参数之间有一个 *?

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

在 HANDLE FileHandle 中,OUT PIO_STATUS_BLOCK IoStatusBlock..输入/输出是什么意思?

这些是注释。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在那里强调所声明的不同类型的名称。

  1. 不,它是一个函数指针。中间的星号只是函数指针正常语法的一部分 - WINAPI只是一个宏。

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

  3. 有一个:PFN_NTQUERYINFORMATIONFILE.

  4. 是的。