假设我有一个接受void (*)(void*)函数指针的函数用作回调函数:
void do_stuff(void (*callback_fp)(void*), void* callback_arg);
Run Code Online (Sandbox Code Playgroud)
现在,如果我有这样的功能:
void my_callback_function(struct my_struct* arg);
Run Code Online (Sandbox Code Playgroud)
我可以安全地这样做吗?
do_stuff((void (*)(void*)) &my_callback_function, NULL);
Run Code Online (Sandbox Code Playgroud)
我已经看过这个问题并且我已经看过一些C标准,它们说你可以转换为'兼容函数指针',但我找不到'兼容函数指针'的含义.
考虑以下C程序:
int f() { return 9; }
int main() {
int (*h1)(int);
h1 = f; // why is this allowed?
return h1(7);
}
Run Code Online (Sandbox Code Playgroud)
根据C11标准,Sec.6.5.16.1,在简单的指配中,"下列之一应持有",列表中唯一相关的一项如下:
左操作数具有原子,限定或非限定指针类型,并且(考虑左值操作数在左值转换后将具有的类型)两个操作数都是指向兼容类型的限定或非限定版本的指针,左侧指向的类型具有全部右边指出的那种限定词;
此外,这是一个"约束",这意味着,一致的实现必须报告诊断消息(如果它被违反).
在我看来,在上述程序的赋值中违反了这种约束.赋值的两端都是函数指针.所以问题是,两种功能类型是否兼容?第二节回答了这个问题.6.7.6.3:
对于要兼容的两种函数类型,两者都应指定兼容的返回类型.146)此外,参数类型列表(如果两者都存在)应在参数数量和省略号终止符的使用中一致; 相应的参数应具有兼容的类型.如果一个类型具有参数类型列表而另一个类型由函数声明符指定,该函数声明符不是函数定义的一部分并且包含空标识符列表,则参数列表不应具有省略号终止符,并且每个参数的类型应为与应用默认参数促销产生的类型兼容.如果一个类型具有参数类型列表而另一个类型由包含(可能为空)标识符列表的函数定义指定,则两者应在参数数量上一致,并且每个原型参数的类型应与类型兼容这是因为默认参数促销应用于相应标识符的类型.
在这种情况下,h1的类型之一具有参数类型列表; 另一个,f,没有.因此,上述引文中的最后一句适用:特别是"两者应在参数数量上达成一致".显然h1需要一个参数.f怎么样?以下几点出现在上述之前:
函数声明符中的空列表是该函数定义的一部分,指定该函数没有参数.
所以很明显f取0个参数.因此,两种类型的参数数量不一致,两种函数类型不兼容,并且赋值违反约束,应该发出诊断.
但是,编译程序时gcc 4.8和Clang都不会发出警告:
tmp$ gcc-mp-4.8 -std=c11 -Wall tmp4.c
tmp$ cc -std=c11 -Wall tmp4.c
tmp$
Run Code Online (Sandbox Code Playgroud)
顺便说一句,如果f被声明为"int f(void)...",两个编译器都会发出警告,但根据我对上述标准的阅读,这不应该是必要的.
问题:
Q1:赋值"h1 = f;" 在上面的程序中违反了约束"两个操作数都指向兼容类型的限定或不合格版本"?特别:
Q2:表达式"h1 = f"中的h1类型是某些函数类型T1的指向T1的指针.究竟什么是T1?
Q3:表达式"h1 = f"中的f类型是某些函数类型T2的指向T2的指针.究竟什么是T2?
问题4:T1和T2兼容吗?(请引用标准或其他文件的相应部分以支持答案.)
Q1',Q2',Q3',Q4':现在假设f的声明改为"int f(void){return 9;}".再次回答问题1-4这个程序.
我目前正在为微处理器编写 C 代码,我遇到了一些我无法解释的事情。我已经使用函数指针实现了命令行界面。为此,我创建了一个结构体,其中包含命令的名称、指向要运行的函数的指针以及帮助说明。
typedef void(*command)(char *);
typedef struct commandStruct {
char const *name;
command execute;
char const *help;
} commandStruct;
const commandStruct commands[] =
{
{"led", CmdLed, "Turns on or off the LED1"},
{"AT+START_SIM", start_simulation, "Starts the simulation"},
{"AT+STOP_SIM", stop_simulation, "Stops the simulation"},
{"",0,""} //End of table indicator.
};
void exec_command(char *buffer)
{
uint16 i = 0;
char *cmd = buffer;
char *args;
while (buffer[i])
{
if(buffer[i] == '=')
{
buffer[i] = 0;
args = buffer + i + 1; …Run Code Online (Sandbox Code Playgroud)