This code does indeed look rather sloppy.
The __cdecl
keyword defines the calling convention: it sets where arguments are supposed to be passed (registers or memory), in what order, which side of the function call is responsible for disposing of them once the function call finishes, and what register state is supposed to be preserved across the call. The extern "C"
declaration controls name mangling as well, i.e. under what name the function is visible to code outside the current translation unit. Neither declaration influences the memory representations of the arguments themselves. Collectively, all those concerns are known as the Application Binary Interface (ABI).
This means that a function signature that declares a C calling convention while simultaneously mentioning types foreign to C is not necessarily useless or meaningless. It’s of course not required that only transitively pure types (those shared between C and C++) should be passed across the C/C++ boundary: it’s expected that sometimes C code may receive opaque (to C) pointers to classes, to structures containing references inside, and so on. However, the presence of types foreign to C directly in the function signature (references, non-POD classes passed by value, non-opaque pointers to such) should be somewhat worrying. It signals whoever wrote that code probably did not think too deeply about ABI stability, or at least did not value it as much as programmer convenience.
Now, a reference is typically represented internally as a pointer, which means that on the C side, one should expect the declaration to behave the same as:
void (*funptr)(const MyStruct *obj);
This is what I think the programmer who wrote that signature had assumed. However, this is not guaranteed. While the C ABI is pretty much set in stone on each platform, the ABI of C++ has historically been much less stable. There is no telling if compilers may some day, for example, start passing const
references to ‘small’ types without mutable
fields as if they were by-value arguments, which might break declarations like mentioned in the question. At the moment this seems unlikely, it is but not entirely outside the realms of possibility.