C++ Migration Guide

Pointers to Functions as Function Parameters

A subtle consequence of the new rule for language linkage involves functions that take pointers to functions as parameters, such as


extern "C" void composer( int(*)(int) );

:.

An unchanged rule about language linkage is that if you declare a function with language linkage, and follow it with a definition of the same function with no language linkage specified, the previous language linkage applies. For example:


extern "C" int f(int);
int f(int i) { ... } // Has "C" linkage

In this example, function f has C linkage. The definition that follows the declaration (the declaration might be in a header file that gets included) inherits the linkage specification of the declaration. But suppose the function takes a parameter of type pointer-to-function, as in the following example:


extern "C" int g( int(*)(int) );
int g( int(*pf)(int) ) { ... } // Is this "C" or "C++" linkage?

Under the old rule, and with the 4.2 compiler, there is only one function g. Under the new rule, the first line declares a function g with C linkage that takes a pointer-to-function-with-C-linkage. The second line defines a function that takes a pointer-to-function-with-C++-linkage. The two functions are not the same; the second function has C++ linkage. Because linkage is part of the type of a pointer-to-function, the two lines refer to a pair of overloaded functions each called g. Code that depended on these being the same function breaks. Very likely, the code fails during compilation or linking.

It is a good programming practice to put the linkage specification on the function definition as well as on the declaration:


extern "C" int g( int(*)(int) );
extern "C" int g( int(*pf)(int) ) { ... }

You can further reduce confusion about types by using a typedef for the function parameter:


extern "C" {typedef int (*pfc)(int);} // ptr to C-linkage function
extern "C" int g(pfc);
extern "C" int g(pfc pf) { ... }