我遇到了一些有趣的东西,我认为应该是有效的。首先:
编译器/版本
$ 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 };
答案 0 :(得分:4)
const char *
与char *
不同。
从C标准6.7.5.3(我强调):
15要兼容两种功能类型,两者都应指定兼容的返回类型。此外,参数类型列表(如果两者都存在)应在数量上一致 参数和省略号终止符的使用; 相应的参数应具备 兼容类型。 [...]
从C标准6.7.5.1(我强调):
2对于两种指针类型兼容,两者都应相同的合格,两者都应 是兼容类型的指针。
注意:const
是qualifier
答案 1 :(得分:2)
基本上你的函数void Foo(const char *abc)
表示我将not modify
我指向的变量。
但是函数运算符void (*exec)(char *abc)
表示我might/mightnot modify
变量。
这是不可接受的。
答案 2 :(得分:2)
只是编译器发现函数签名不匹配并发出警告而不是错误,因为函数调用在运行时可以正常工作(相同类型/大小/函数数量) PARAMS)。
警告背后的明显原因是帮助程序员识别功能指针被意外分配的功能,该功能偶然接受相同的参数但操作明显不同。
在当前示例中,编译器可以根据应用于函数参数的
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;
在这种情况下,只要满足返回类型约束,编译器就不会发出警告。
答案 3 :(得分:0)
仅仅是这方面的任务就可以了,例如
char * a = <whatever>;
const char * b = a;
但在函数签名中,规则比赋值更严格。
答案 4 :(得分:0)
您的函数foo
和函数指针exec
的签名是不同的。
编译器知道变量是const,并且根据编译器,编译器可能会进行一些优化。