[英]What does this typedef declaration mean?
我知道 C 中的typedef
,但当我看到 K&R 书中的声明时,我感到困惑。 声明是
typedef int (*PFI) (char *,char *)
这是什么意思? 什么是PFI
以及我们如何在我们的程序中使用它?
分解它, PFI
是一个指针:
*PFI
对于 function:
(*PFI)()
这需要两个char *
类型的 arguments :
(*PFI)(char *, char *)
并返回一个int
:
int (*PFI)(char *, char *)
并声明为该类型的别名:
typedef int (*PFI)(char *, char *);
如果您有一个与此指针类型匹配的 function ,则可以使用它,即:
int foo(char *x, char *y)
{
...
}
然后,您可以将指向 function 的指针分配给PFI
类型的变量:
PFI *f = &foo;
您在阅读有关指向函数的指针吗?
如果是,那么 PFI 只是一个占位符。 它可以是您提供的任何名称,它只是一个 function 名称。 我想这可能意味着“首选 Function 接口”,但这只是一个猜测。
所以假设你写了一个非常粗糙的代码,比如
typedef bool (*write_X_Bytes) (uint32 count, char *buffer);
那么您可以将它用作 C 中的类型,因为您在它前面使用了 typedef
write_X_Bytes print_line, print_word;
基本上你给用户或任何想要使用这个关于参数和返回的代码的人提供一个原型。 您可以查看 GPIO 的 Linux kernel 驱动程序代码以用于实际用例。
指针声明的基本规则:
T *p; // p is a pointer to T
T *ap[N]; // ap is an N-element array of pointers to T
T *fp(); // fp is a function returning a pointer to T
T (*pa)[N]; // pa is a pointer to an array of T
T (*pf)(); // pf is a pointer to a function returning T
在表达式和声明符中,下标[]
和 function call ()
运算符的优先级高于一元解引用*
运算符,因此像*f()
这样的表达式或声明符被解析为*(f())
- 您正在解引用f
的结果。 如果要在调用f
之前取消引用它,则必须将*
运算符与它显式分组 - (*f)()
。
阅读毛茸茸的声明的方法是从最左边的标识符开始,按照上面的规则,递归地将它们应用于任何 function 参数。
如果您有一个 function 像这样在参数列表中使用抽象声明符,请记住:
T * -> T *λ
T *[N] -> T *λ[N]
T (*)[N] -> T (*λ)[N]
T *() -> T *λ()
T (*)() -> T (*λ)()
其中λ
表示标识符通常位于 go 的位置。
所以,阅读这个声明的方式是
PFI -- PFI
typedef PFI -- is a typedef name for
typedef *PFI -- pointer to
typedef (*PFI) ( ) -- a function taking
typedef (*PFI) ( ) -- unnamed parameter
typedef (*PFI) ( * ) -- is a pointer to
typedef (*PFI) (char * ) -- char
typedef (*PFI) (char *, ) -- unnamed parameter
typedef (*PFI) (char *, *) -- is a pointer to
typedef (*PFI) (char *,char *) -- char
typedef int (*PFI) (char *,char *); -- returning int
用不太正式的术语来说,PFI 是“指向 function 的指针,采用两个char *
参数并返回int
”类型的别名。
那么我们将如何使用它呢?
一个常见的用途是在 function 参数列表中声明回调:
void foo( char *foo, char *bar, PFI callback )
{
int x = callback( foo, bar );
...
}
这比阅读要容易一些
void foo( char *foo, char *bar, int (*callback)(char *, char *) )
{
int x = callback( foo, bar );
...
}
它对于声明 arrays 或struct
成员也很有用:
int func1( char *x, char *y ) { ... }
int func2( char *a, char *b ) { ... }
...
struct s {
char *x;
char *y;
PFI f;
} blah = {"foo", "bar", func1};
PFI callbacks[] = { func1, func2, ... };
再一次,这比写作要干净一些
struct s {
char *x;
char *y;
int (*f)(char *, char *);
};
或者
int (*callbacks[])(char *, char *) = { func1, func2, ... };
但...
“稍微干净一点”本身并不是将类型隐藏在typedef
后面的充分理由。 您使用typedef
来抽象出有关该类型的用户不需要知道才能使用它的类型的详细信息。
例如,考虑stdio.h
中的FILE
类型。 有一个完整的 API 支持FILE
类型,因此您永远不需要知道它在引擎盖下的样子。
然而,在我们的例子中,我们必须知道PFI
是指向 function 的指针,需要两个char *
arguments 并返回一个int
才能使用它。 使用 typedef 名称节省了一些击键,但它也创建了一个“泄漏”的抽象,因为有关类型的详细信息必须“泄漏”给程序员。 在这种情况下,最好完全放弃typedef
并使用“naked”声明。
https://cdecl.org/说“将 PFI 声明为指向 function(指向 char 的指针,指向 char 的指针)返回 int 的指针”。 该网站不喜欢最初的 typedef,但这使它成为一种类型,因此您可以编写:
PFI fp = f;
其中f
将具有原型:
int f(char *, char *);
PFI 只是表示“指向 function 返回 int 的指针”。 这是创建可在代码中快速使用的类型的快速方法,否则语法会很复杂。
例如,它对于回调接口非常有用。 您可能希望将 PFContext_t 之类的东西定义为指向 function 的指针,它采用特定的 arguments 并返回上下文指针。 然后你可以在你的数据中使用typedef(例如,如果你想将指针保留在一个结构中),你可以将arguments中的typedef用于客户端调用的function,设置回调。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.