Convert C++ Function Pointer to C Function Pointer

Convert C++ function pointer to c function pointer

If I recall it correctly, Only static methods of a class can be accessed via "normal" C pointer to function syntax. So try to make it static. The pointer to a method of a class needs extra information, such as the "object" (this) which has no meaning for a pure C method.

The FAQ shown here has good explanation and a possible (ugly) solution for your problem.

Is it safe to cast a function pointer to another function pointer in C?

Is it safe to cast these 2 functions to callback pointer type then call them without casting back?

No. The types of the two functions are not compatible with type callback, in the language specification's sense of "compatible", therefore calling either of those functions via a pointer of type callback invokes undefined behavior. Overall, non-variadic function types are never compatible with variadic ones, and in practice, many implementations use different calling conventions for one type than for the other, such that there is no plausible reason even to hope that calling a function of one variety as if it were of the other variety would have the desired effect in any consistent way.

You have several alternatives, among them:

  • Use different callback types for different purposes, each appropriate to its intended callback interface. This way you can avoid casting the callback functions at all. This would be my recommendation. It achieves the best type safety, and you need somehow to keep track of what the actual callback type is anyway, so that you can call it correctly.

  • Use a union of function pointer types. Callback specifiers assign to the appropriate member of the union, and callback callers select the appropriate member.

    typedef union {
    int (*unary)(int i);
    int (*binary)(int i, int j);
    } callback;

    // ...

    callback cb1 = { .unary = foo };
    callback cb2 = { .binary = foo2 };
    cb1.unary(1);
    cb2.binary(1, 2);

    You might even use a tagged union -- one that additionally carries information about which member is used. That would be a bit more complicated to use, but it would give you a means to achieve additional type safety. One of the variations on this approach would be my fallback recommendation if you need a single data type with which multiple callback types can be conveyed.

  • Choose a single callback type that meets all your needs. One way to do that would be to give it a parameter of type void *, by which callback functions can accept any number and type of inputs by, for example, a pointer to a suitable structure type.

    typedef int (*callback)(void *);
    struct one_int { int i1; };
    struct two_int { int i1, i2; };
    int foo(void *args) {
    struct one_int *one_int = args; // ...
    }
    int foo2(void *args) {
    struct two_int *two_int = args; // ...
    }
  • Choose any function type as callback. Cast to that type going in, and back to the original type for calls.

  • Specify the callback type without a prototype. In C, if a function declaration that is not part of a definition of that function does not specify a parameter type list then that means that no information is provided about the parameters (unlike in C++, where that means that the function has no parameters). That is compatible with functions requiring any specific number of arguments -- but not variadic ones -- provided that applying the default argument promotions to the parameter types yields compatible types. Type int is a fine parameter type in that regard. The main ones that would be a problem are integer types narrower than int, plus float.

    typedef int (*callback)();

    This would allow exactly the usage you describe for the particular function types in your example.

    callback cb1 = foo;
    callback cb2 = foo2;

    (*cb1)(1); // or just cb1(1)
    (*cb2)(1, 2); // or just cb2(1, 2)

    Contrary to another answer's claim, support for this approach does not constitute an extension to any version of the C language specification published to date. Supporting it is a requirement for conformance with any of C89, C99, C11, and C17. However, it has been declared "obsolescent" in C17, which constitutes a warning that it may be removed from some future version of the language specification. I expect that it indeed will be removed, possibly as soon as the next version of the specification, though obsolescence does not guarantee that.

Assign C++ member function to C function pointer

You simply cannot do this. Member functions have an implicit this argument that is a pointer to the object on which the function is being called. A function that does not take a B* as an argument will never manage to run on a specific B instance and a function that does not take this point as its first argument can never have the same signature as a class method. For more details on this problem and an example of a workaround read:

https://isocpp.org/wiki/faq/pointers-to-members#memfnptr-vs-fnptr

Pay attention to the note at the bottom of the answer on how static member functions can be used in such manner.

Pure C++ projects can use std::function & std::bind to achieve what you are asking about, but a C library used by a C++ project cannot work with these types.

Returning a Function Pointer from a Function and Calling it with a Pointer. How does this Work Exactly?

Can someone tell how exactly does this work? Does it have to do with
assigning (*ptr)(int, int) the function's address or something?

Function Convert() returns a pointer to a function -- either a pointer to Sum() or a pointer to Difference(), depending on its argument (or it terminates without specifying a return value, which is bad news for you if you do anything at all with the return value). That function pointer is stored in variable ptr, which is declared to have the same type as Convert() returns. The pointed-to function can then be called by use of the function-call operator, ().

Perhaps it would be a bit clearer if rewritten in this equivalent way, with use of a typedef:

typedef int (*op_function)(int, int);

op_function Convert(const char code) {
if (code == ‘+’) return ∑ // Takes two ints, and adds
if (code == ‘-’) return &Difference; // Takes two ints, and subtracts
}

int main () {
op_function ptr;
ptr = Convert(‘+’);
printf( “%d\n”, ptr(2,4));
}

Is conversion of a function pointer to a uintptr_t / intptr_t invalid?

Is conversion of a function pointer to a uintptr_t / intptr_t invalid?

No. It may be valid. It may be undefined behavior.


Conversion of a function pointer to ìnt* is not defined. Nor to any object pointer. Nor to void *.

pdata = ( int * ) pfunc; is undefined behavior.

Conversion of a function pointer to an integer type is allowed, with restrictions:

Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type. C17dr 6.3.2.3 6

Also integer to a pointer type is allowed.

An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation. C17dr 6.3.2.3 6

void * to integer to void * is defined. Object pointer to/from void* is defined. Then the optional (u)intptr_t types are sufficient for round-trip success. Yet we are concerned about a function pointer. Often enough function pointers are wider than an int *.

Thus converting a function pointer to int * only makes sense through an integer type, wider the better.

VS may recommend through the optional type uintptr_t and is likely sufficient if information is lossless on other platforms. Yet uintmax_t may afford less loss of information, especially in the function pointer to integer step, so I pedantically suggest:

pdata = ( int * ) (uintmax_t) pfunc;

Regardless of the steps taken, code is likely to become implementation specific and deserves guards.

#ifdef this && that
pdata = ( int * ) (uintmax_t) pfunc;
#else
#error TBD code
#endif

C++-17: cast function pointer to function with different argument pointer type

No, this is not safe and is explicitly called out as undefined behavior in [expr.call]/6

Calling a function through an expression whose function type is different from the function type of the called function's definition results in undefined behavior.

This is also reinforced in the reinterpret_cast documentation about function pointer conversions [expr.reinterpret.cast]/6

A function pointer can be explicitly converted to a function pointer of a different type. [ Note: The effect of calling a function through a pointer to a function type ([dcl.fct]) that is not the same as the type used in the definition of the function is undefined ([expr.call]). — end note ] Except that converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified. [ Note: See also [conv.ptr] for more details of pointer conversions. — end note ]

Casting a function pointer to another type

As far as the C standard is concerned, if you cast a function pointer to a function pointer of a different type and then call that, it is undefined behavior. See Annex J.2 (informative):

The behavior is undefined in the following circumstances:

  • A pointer is used to call a function whose type is not compatible with the pointed-to
    type (6.3.2.3).

Section 6.3.2.3, paragraph 8 reads:

A pointer to a function of one type may be converted to a pointer to a function of another
type and back again; the result shall compare equal to the original pointer. If a converted
pointer is used to call a function whose type is not compatible with the pointed-to type,
the behavior is undefined.

So in other words, you can cast a function pointer to a different function pointer type, cast it back again, and call it, and things will work.

The definition of compatible is somewhat complicated. It can be found in section 6.7.5.3, paragraph 15:

For two function types to be compatible, both shall specify compatible return types127.

Moreover, the parameter type lists, if both are present, shall agree in the number of
parameters and in use of the ellipsis terminator; corresponding parameters shall have
compatible types. If one type has a parameter type list and the other type is specified by a
function declarator that is not part of a function definition and that contains an empty
identifier list, the parameter list shall not have an ellipsis terminator and the type of each
parameter shall be compatible with the type that results from the application of the
default argument promotions. If one type has a parameter type list and the other type is
specified by a function definition that contains a (possibly empty) identifier list, both shall
agree in the number of parameters, and the type of each prototype parameter shall be
compatible with the type that results from the application of the default argument
promotions to the type of the corresponding identifier. (In the determination of type
compatibility and of a composite type, each parameter declared with function or array
type is taken as having the adjusted type and each parameter declared with qualified type
is taken as having the unqualified version of its declared type.)

127) If both function types are ‘‘old style’’, parameter types are not compared.

The rules for determining whether two types are compatible are described in section 6.2.7, and I won't quote them here since they're rather lengthy, but you can read them on the draft of the C99 standard (PDF).

The relevant rule here is in section 6.7.5.1, paragraph 2:

For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.

Hence, since a void* is not compatible with a struct my_struct*, a function pointer of type void (*)(void*) is not compatible with a function pointer of type void (*)(struct my_struct*), so this casting of function pointers is technically undefined behavior.

In practice, though, you can safely get away with casting function pointers in some cases. In the x86 calling convention, arguments are pushed on the stack, and all pointers are the same size (4 bytes in x86 or 8 bytes in x86_64). Calling a function pointer boils down to pushing the arguments on the stack and doing an indirect jump to the function pointer target, and there's obviously no notion of types at the machine code level.

Things you definitely can't do:

  • Cast between function pointers of different calling conventions. You will mess up the stack and at best, crash, at worst, succeed silently with a huge gaping security hole. In Windows programming, you often pass function pointers around. Win32 expects all callback functions to use the stdcall calling convention (which the macros CALLBACK, PASCAL, and WINAPI all expand to). If you pass a function pointer that uses the standard C calling convention (cdecl), badness will result.
  • In C++, cast between class member function pointers and regular function pointers. This often trips up C++ newbies. Class member functions have a hidden this parameter, and if you cast a member function to a regular function, there's no this object to use, and again, much badness will result.

Another bad idea that might sometimes work but is also undefined behavior:

  • Casting between function pointers and regular pointers (e.g. casting a void (*)(void) to a void*). Function pointers aren't necessarily the same size as regular pointers, since on some architectures they might contain extra contextual information. This will probably work ok on x86, but remember that it's undefined behavior.

Implicit cast from function to function pointer?

Yes, there's function-to-pointer implicit conversion:

An lvalue of function type T can be implicitly converted to a prvalue pointer to that function. This does not apply to non-static member functions because lvalues that refer to non-static member functions do not exist.

And

A pointer to function can be initialized with an address of a non-member function or a static member function. Because of the function-to-pointer implicit conversion, the address-of operator is optional:

void f(int);
void (*p1)(int) = &f;
void (*p2)(int) = f; // same as &f

That means when being used in context requiring a function pointer, function (except for non-static member function) would convert to function pointer implicitly, and the usage of operator& is optional.



Related Topics



Leave a reply



Submit