例如我有这 3 个函数和函数指针:
char *(*f)(char, int);
char *(*g(char, int));
char **h(char, int);
Run Code Online (Sandbox Code Playgroud)
如果我们将它们翻译成英文,我们会得到:
将 f 声明为指向函数 (char, int) 的指针,返回指向 char 的指针
将 g 声明为函数 (char, int) 返回指向 char 的指针
将 h 声明为函数 (char, int) 返回指向 char 的指针
类型 2. 和类型 3. 是相等的。我们可以检查一下吗,也许是这样的:
if(g==h)
{
do something;
}
Run Code Online (Sandbox Code Playgroud)
在c中?
c 也允许类似的东西吗g=h?(如果是,它实际上是做什么的?)
这样的比较是有效的:
if(g==h)
Run Code Online (Sandbox Code Playgroud)
因为函数名在表达式中使用时会自动转换为函数指针,并且允许比较任意两个函数指针是否相等。在这种情况下,它将评估为 false,因为g和h是两个不同的函数,因此它们的地址始终不同。
但是,您不能执行以下任一操作:
f = g;
f = h;
Run Code Online (Sandbox Code Playgroud)
因为与或f不兼容。尝试这样做可能会从编译器中生成警告:&g&h
if(g==h)
Run Code Online (Sandbox Code Playgroud)
如果您将类型更改为:
char **(*f)(char, int);
Run Code Online (Sandbox Code Playgroud)
然后它们就会兼容,你可以这样做:
f = g;
if (f==g) { // true
printf("f is g\n");
}
Run Code Online (Sandbox Code Playgroud)
另外,g=h也是不允许的,因为函数名称是不可修改的左值,这本质上意味着它们不能更改。
要在编译时测试类型,您可以使用带有_Generic. 我做了一个概念证明:
#include <stdio.h>
#define GETTYPE(fp) _Generic \
( \
(fp) \
, char *(*)(char, int) : 1 \
, int *(*)(char, int) : 2 \
, int *(*)(char*, int) : 3 \
, char **(*)(char, int) : 4 \
)
extern char *a(char,int);
extern int *b(char,int);
extern int *c(char*,int);
extern char **d(char,int);
extern char *a1(char,int);
int main(int argc, char **argv)
{
(void)argc;
(void)argv;
printf("type a %i\n",GETTYPE(a));
printf("type b %i\n",GETTYPE(b));
printf("type c %i\n",GETTYPE(c));
printf("type d %i\n",GETTYPE(d));
printf("type a==a1? %i\n",GETTYPE(a)==GETTYPE(a1));
printf("type b==a1? %i\n",GETTYPE(b)==GETTYPE(a1));
printf("type c==a1? %i\n",GETTYPE(c)==GETTYPE(a1));
printf("type d==a1? %i\n",GETTYPE(d)==GETTYPE(a1));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该GETTYPE宏将每个列出的类型转换为一个值。然后可以使用该值来存储类型并进行比较。更好的版本会使用 aenum来定义值,但您可以自己这样做。
必须在您仍然持有原始函数指针(或使用衰减为函数指针的实际函数)时调用宏。为什么这是显而易见的,但这限制了它的用例。如果要保留有关类型的信息,则需要为每个类型分配一个数字并将其存储在通用函数指针中。当需要函数指针时,可以根据类型号将其转换回原始类型。这需要大量的手工工作,因为您需要单独处理每种需要的类型。