В C, когда вы вызываете функцию без видимого прототипа, продвижения аргументов по умолчанию применяются ко всем аргументам, которые вы передаете функции. Это означает, что типы, которые вы фактически передаете, не обязательно соответствуют типам, полученным функцией.
* 1005 Е.Г. *
void (*g)();
void f()
{
float x = 0.5;
g(x); // double passed
}
Это означает, что вам нужно знать, что функция, которую вы на самом деле вызываете, имеет подпись, совместимую с аргументами, которые вы передаете после повышения.
Учитывая, что вам нужно знать это в любом случае, вы должны знать сигнатуру функции фактической функции, вызываемой на сайте вызова, который использует указатель функции. Обладая этими знаниями, обычно проще и чище использовать указатель на функцию с правильным прототипом, и вы можете полностью избежать использования аргументов по умолчанию.
Обратите внимание, что когда вы определяете свои функции с помощью прототипов, когда вы назначаете указатель на свою функцию на указатель на функцию без прототипа, вы эффективно преобразуете, скажем, void(*)(int, int)
в void(*)()
, так что это совершенно правильно и желательно выполнить обратное преобразование перед вызовом функции. gcc разрешает оба этих преобразования без предупреждения.
* 1016 Е.Г. *
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 );
}
}