5

我遇到了一些有趣的事情,我认为应该是有效的。首先:

编译器/版本

$ gcc --version
gcc (Debian 4.7.2-5) 4.7.2

编译器选项和警告消息。

$ gcc -c warn.c -o warn.o
warn.c:11:5: warning: initialization from incompatible pointer type [enabled by default]
warn.c:11:5: warning: (near initialization for ‘foo.exec’) [enabled by default]

我想知道为什么 'Foo()' 与 'exec' 不兼容。(添加评论以希望完全清晰)

typedef struct Thing
{
    void (*exec)(char *abc);
} Thing;

// ME: I don't mess with this.. I make const, K?
void Foo(const char *abc)
{
    (void) abc;
}

// GCC: LOL, nope! probably u messed up.
Thing foo = { Foo };
4

5 回答 5

4

const char *不一样char *

从 C 标准 6.7.5.3(我强调):

15 对于要兼容的两种函数类型,两者都应指定兼容的返回类型。此外,参数类型列表(如果两者都存在)应在参数数量和省略号终止符的使用方面达成一致;相应的参数应具有兼容的类型。[...]

从 C 标准 6.7.5.1(我强调):

2 对于要兼容的两种指针类型,两者都应具有相同的限定,并且都应是指向兼容类型的指针。

注:const是一个qualifier

于 2013-08-27T06:47:09.860 回答
2

基本上你的函数void Foo(const char *abc)说我将not modify我指向的变量。

但是函子 int srtuctvoid (*exec)(char *abc)说我might/mightnot modify是变量。

这是不可接受的。

于 2013-08-27T06:54:07.673 回答
2

只是编译器在函数签名中发现不匹配并发出警告而不是错误,因为函数调用在运行时可以正常工作(相同的类型/大小/函数参数数量)。

警告背后的明显原因是帮助程序员识别函数指针被意外分配一个函数的情况,该函数同时接受相同的参数但其操作明显不同。

在当前示例中,编译器可以根据const应用于函数参数的修饰符隐含的意图差异来识别这一点。


基本上当您定义struct如下时,

typedef struct Thing
{
    void (*exec)(char *abc);
} Thing;

您明确告诉编译器函数指针应仅指向与特定签名(参数和返回类型)匹配的函数。

通过如下更新定义可以轻松修复此警告struct

typedef struct Thing
{
    void (*exec)(const char *abc);
} Thing;

或者可以通过完全不指定参数来完全回避

typedef struct Thing
{
    void (*exec)();
} Thing;

在这种情况下,只要满足返回类型约束,编译器就不会发出警告。

于 2013-08-27T07:00:26.067 回答
0

仅在这个方向上分配就可以了,例如

char * a = <whatever>;
const char * b = a;

但在函数签名中,规则比分配更严格。

于 2013-08-27T06:48:09.320 回答
0

您的函数的签名foo和函数指针exec是不同的。

编译器知道变量是 const 并且根据编译器,编译器可能会进行一些优化。

于 2013-08-27T07:12:30.750 回答