C99:使用不同数量的参数转换回调

Iva*_*ono 8 c pointers casting function c99

在下面的示例中,我在指向应接收参数的函数的指针中创建了一个没有参数的函数的 CAST。假设它给出了预期的结果,这个过程是否有可能导致一些故障?在线测试:https : //onlinegdb.com/SJ6QzzOKI

typedef void (*Callback)(const char*);
Callback cb;

void inserisce_cb(void* c) {
    cb=c;
}

void esegue_cb(){
    cb("pippo");
}

void scriveTitolo(const char* titolo) {
    Uart_Println(titolo);
}

void scriveTitolo2() {
    Uart_Println("pluto");
}

void main(){
    inserisce_cb(scriveTitolo);
    esegue_cb();
    inserisce_cb(scriveTitolo2);
    esegue_cb();
}
Run Code Online (Sandbox Code Playgroud)

Eri*_*hil 4

将一个函数的指针转换为另一个函数的指针是由 c 标准定义的,但根据 C 6.3.2.3 8,使用生成的指针来调用具有不兼容类型的函数则不是:

\n\n
\n

指向一种类型函数的指针可以转换为指向另一种类型函数的指针,然后再转换回来;结果应等于原始指针。如果转换后的指针用于调用其类型与引用类型不兼容的函数,则行为未定义。

\n
\n\n

该声明void scriveTitolo2() { \xe2\x80\xa6 }定义了一个没有参数类型列表的函数(它使用旧的 C 风格的标识符列表,该列表为空)并且不带任何参数。指针Callback指向具有参数类型列表并接受const char *参数的函数。根据 C 2018 6.7.6.3 15,这些是不兼容的:

\n\n
\n

为了使两个函数类型兼容,\xe2\x80\xa6 如果一种类型具有参数类型列表,而另一种类型由包含(可能为空)标识符列表的函数定义指定,则两者的参数数量应一致,\xe2\x80\xa6

\n
\n\n

由于它们在参数数量上不一致,因此它们是不兼容的。

\n\n

上面只讲了从void (*)()到 的转换void (*){const char *)以及使用结果来调用函数的问题。还有一个单独的问题,函数指针传递给inserisce_cb,它接受类型 的参数void *,该参数是指向对象类型的指针。C 标准没有定义将函数类型指针转换为对象类型指针的行为。为了解决这个问题,inserisce_cb应该声明一个指向函数类型的指针,例如void inserisce_cb(Callback c).

\n\n

如果scriveTitolo2可以更改,则可以通过将其更改为采用const char *未使用的参数,将其定义更改为来解决兼容性问题void scriveTitolo2(const char *)解决兼容性问题。

\n\n

(请注意,最好scriveTitolo2使用现代 C 风格 as进行声明void scriveTitolo2(void) { \xe2\x80\xa6 },而不是不使用void。这与问题无关,因为它不会使函数类型兼容,但这种声明格式为编译器提供了更多信息很多情况。)

\n