[英]How do I quiet the C compiler about a function pointer takes any number of arguments?
我在一个struct
中有一个 function 指针,该指针在运行时动态设置为我代码中不同位置的另一个 function 的地址。 它在我的 header 文件中定义如下:
void *(*run)();
在编译期间,我收到以下警告:
warning: function declaration isn't a prototype
这个警告是良性的,因为在我的代码中的许多地方都使用了指针来调用它指向的 function,并且一切正常。 但是,我真的很想消除警告。
如果我将其更改为:
void *(*run)(void);
无论我使用它,我都会遇到编译错误,因为使用指针的各种函数具有不同数量的 arguments,并且括号内的void
告诉编译器它不接受 arguments。
我不能使用va_list
或任何类似的东西,因为这只是指向另一个 function 的指针,我对它们都使用单个指针,因为它使代码保持简洁。
我可以通过将其添加到我的编译器标志来使警告静音:
-Wno-strict-prototypes
但是,如果可以避免的话,我宁愿不必禁用带有标志的编译器警告。
所以我的问题是:我如何在代码中注释这个 function 指针,以使编译器对它接受任意数量的任何类型的 arguments 这一事实感到满意?
该代码完美运行。 我只想要 go 的警告。
将指针存储为void *
并在必要时转换为适当的 function 指针类型? 请记住,将一种类型的 function 指针调用为另一种类型并不一定安全,因此您开始使用的警告并非完全无效。
您可以像这样转换 function 指针:
void *genericPointer = ...;
void (*fp)(int, int) = genericPointer;
fp(123, 456);
注意:
void *
总是可以转换为任何指针类型。(*fp)
之前的初始“void”是 function 指针的返回类型。您正在尝试做干净的事情 - 即让编译器参与检查,但是您发明的设计根本无法按照其原理进行清洁。 您不能以这种方式让编译器参与原型检查,因为您始终必须知道在运行时的这种特殊情况下要传递哪些参数。 编译器无法检查这一点,如果你犯了错误,就会出现分段错误。
但如果我没记错的话,linux kernel(?)中也可能使用过类似的东西。 解决方案是拥有一个通用指针(就像您拥有的那样),每次调用特定的 function 时,您只需将其类型转换为指向 function 的指针,并带有特定的 ZDBC11CAA5BDA99F77E6FB4DABD882E7。 您可能需要先将其类型转换为 void * 以再次使编译器静音:-)
In C, when you call a function without a prototype visible, default argument promotions are applied to all of the arguments that you pass to the function. 这意味着您实际传递的类型不一定与 function 接收的类型匹配。
例如
void (*g)();
void f()
{
float x = 0.5;
g(x); // double passed
}
这意味着您需要知道您实际调用的 function 与您在升级后传递的 arguments 所暗示的签名兼容。
鉴于您在任何情况下都需要知道这一点,您必须知道在使用 function 指针的调用站点上调用的实际 function 的 function 签名。 有了这些知识,使用具有正确原型的 function 指针通常更简单、更清晰,并且您可以完全避免默认参数提升。
请注意,当您使用原型定义函数时,当您将指向 function 的指针分配给没有原型的 function 指针时,您可以有效地将void(*)(int, int)
转换为void(*)()
因此在调用 function 之前执行反向转换是完全正确和可取的。 gcc 允许这两种转换而不会发出任何警告。
例如
void PerformCall( void(*p)() )
{
if (some_condition)
{
// due to extra knowledge I now know p takes two int arguments
// so use a function pointer with the correct prototype.
void(*prototyped_p)(int, int) = p;
prototyped_p( 3, 4 );
}
}
尝试 typedefing function 指针声明,然后让调用者显式地转换它:
typedef void *(*run)();
//when calling...
void my_foo() {}
run r = (run)my_foo;
如果已知不同的 function 签名,请使用union
。 否则,使用void (*)(void)
类型的指针(实际上,任何 function 指针类型都可以)来保存通用指针并在设置值和调用代码时转换为正确的类型。
使用union
的示例:
union run_fn
{
void *(*as_unary)(int);
void *(*as_binary)(int, int);
};
struct foo
{
union run_fn run;
};
void *bar(int, int);
struct foo foo;
foo.run.as_binary = bar;
void *baz = foo.run.as_binary(42, -1);
使用显式强制转换的示例:
struct foo
{
void (*run)(void);
};
void *bar(int, int);
struct foo foo;
foo.run = (void *(*)(int, int))bar;
void *baz = ((void *(*)(int, int))foo.run)(42, -1);
不要使用void *
来保存 function 指针 - ISO C 标准未指定此类转换,并且可能在某些架构上不可用。
忽略警告并按原样使用代码实际上也是一种可能性,但请记住,任何 function 参数都将受到默认参数提升的影响,提升的 arguments 与声明的参数正确匹配是您的责任。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.