I am working on code that needs to send a member function pointer to a logger method that accepts a void * as the parameter. I cannot change it from void *. I cannot use c++11 either. Is there a way to get it to work without any warning. For example:
logger.h
#ifndef _LOGGER_H
#define _LOGGER_H
void logger( void *func );
#endif /* _LOGGER_H */
logger.cpp
#include <cstdio>
#include "logger.h"
void logger( void *func )
{
printf("%lx\n", (unsigned long)func);
}
testCase.cpp
#include "logger.h"
class myClass
{
public:
void testCase( void );
};
void myClass::testCase( void )
{
/* This works on my compiler, but gives warning */
/* warning: converting from 'void (myClass::*)()' to 'void*' */
/* I know this is bad and wrong. */
logger((void *)&myClass::testCase);
/* This compiles without warning */
/* But doesnt work the way I need, gives ffff*/
void (myClass::*ptr)( void ) = &myClass::testCase;
void *m_ptr = ptr;
logger(m_ptr);
}
logger.h and logger.cpp cannot be changed.
This is being run a VxWorks and I need the address to look up in the symbol table. When I try the second way I get ffff. Although I get a real address when using other compilers, its different for VxWorks.
Can you think of another way to get this to work.
References
No, you can't make it happen. Standard prohibits converting pointers-to-members to void*. The reason for this is their incompatibility with void* - they are usually double the size of the void*.
Your code has other issues as well, for example, (unsigned long)func is converting a void* to unsigned long, and this is undefined as well. For example, on many systems long is 32 bits in length, while void* is 64bit. To reliably convert void* to integer type, you need to use uintptr_t (provided your implementation has it).
I don't know about "double the size"; pointers are pointers and in my understanding, all pointers on a given system are the same size, regardless of what they point to...
However, looking in my copy of The C++ Programming Language, 3rd Edition, by Stroustrup (page 101):
Occurrances of void*s at higher levers of the system should be viewed with suspicion because they are likely indicators of design errors. Where used for optimization, void* can be hidden behind a type safe interface (§13.5, §24.4.2).
Pointers to functions (§7.7) and pointers to members (§15.5) cannot be assigned to void*s.
Related
I am writing a bootloader for an STM32, where I need to jump from bootloader to the real app.
In C this works, because I can cast an address to a void pointer and assign that to a function pointer, and call the function pointer as follows:
void jump_to_firmware(uint32_t address)
{
uint32_t reset_handler_add = *((volatile uint32_t *)(address + 4));
void (*app_reset_handler)(void) = (void *)reset_handler_add;
SCB->VTOR = address;
uint32_t msp_value = *((volatile uint32_t *)address);
__set_MSP(msp_value);
app_reset_handler();
}
If I use the same implementation in a C++ the gnu compiler will give an error on the cast to void pointer.
include/bootloader.hpp:58:39: error: invalid conversion from 'void*'
to 'void (*)()' [-fpermissive]
After googling I found this SO page, which I tried and came to the following implementation in my class:
void JumpToApp()
{
// Quick test if C style cast does work
//jump_to_firmware(_appStartAddress);
uint32_t mspAdress = *((volatile uint32_t *)_appStartAddress);
uint32_t resetHandlerAddress = *((volatile uint32_t *)(_appStartAddress + sizeof(uint32_t)));
// https://stackoverflow.com/questions/1096341/function-pointers-casting-in-c
typedef void (*functionPointer)();
functionPointer resetHandler = 0;
reinterpret_cast<void*&>(resetHandler) = (void*)resetHandlerAddress;
SCB->VTOR = _appStartAddress;
__set_MSP(mspAdress);
resetHandler();
}
In the C++ implementation:
functionPointer resetHandler is assigned with 0x8035065
SCB->VTOR is assigned with 0x08020000
mspAddress is assigned with `0x20020000
then the function pointer resetHandler is called
In the C implementation:
app_reset_handler is assigned with 0x8035065
SCB->VTOR is assigned with 0x08020000
mspAddress is assigned with `0x20020000
then the function pointer app_reset_handler is called
The C implementation works, it jumps to my app, the app runs without issues.
The C++ implementation ends up nowhere. It hangs/crashes on the following (to me meaningless) address:
I am trying to keep the amount of source files to a minimum, so I would like to keep the logic in the single class definition.
My questions:
Did I misunderstand the linked SO page and can somebody see where I went wrong in the C++ implementation?
Is there a better/easier way to cast an address to a function pointer in C++?
Or is there a technical reason why it simply can't be done in C++?
PS: The bootloader code is the same in both cases. The only difference I made to test either implementation is to comment out the code in Bootloader::JumpToApp and call the C function jump_to_firmware(uint32_t) instead.
PPS: all peripherals are deinitialized properly. Again, it works fine, the problem only appears when I use this C++ implementation.
The same code will compile in C and C++. You simple has to cast to the correct cast (in C++ you cant assign a void * to non void * pointer. It is much more strict than in C.
void jump_to_firmware(uint32_t address)
{
uint32_t reset_handler_add = *((volatile uint32_t *)(address + 4));
void (*app_reset_handler)(void) = (void (*)(void))reset_handler_add;
/* ... */
}
If you do not like those weird casts you can typedef the function.
typedef void handler(void);
void jump_to_firmware(uint32_t address)
{
uint32_t reset_handler_add = *((volatile uint32_t *)(address + 4));
handler *app_reset_handler = (handler *)reset_handler_add;
/* ... */
}
I have a function like this:
typedef long long myint64;
typedef enum {
INT32_FIELD,
CHARP_FIELD,
INT64_FIELD,
} InfoType;
int32_t ReadInfo(void *handle, InfoType info, ...)
{
va_list arg;
va_start(arg, info);
void *argPtr = va_arg(arg, void*);
va_end(arg);
int32_t ret = 0;
int32_t *paramInt = NULL;
char **paramCharp = NULL;
myint64 *paramInt64 = NULL;
switch (info) {
case INT32_FIELD:
paramInt = static_cast<int32_t*>(argPtr);
*paramInt = functionWhichReturnsInt32();
break;
case CHARP_FIELD:
paramCharp = static_cast<char**>(argPtr);
*paramCharp = functionWhichReturnsCharPtr();
break;
case INT64_FIELD:
paramInt64 = static_cast<myint64*>(argPtr);
*paramInt64 = functionWhichReturnsInt64();
break;
default:
ret = -1;
break;
}
return ret;
}
Call this function like this from separated c file. This file does not include definition of ReadInfo function:
extern "C" {int32_t CDECL ReadInfo(intptr_t, int32_t, int32_t*);}
int32_t readInt()
{
int32_t value = 0;
int32_t *ptr = &value;
ReadInfo(handle, INT32_FIELD, ptr);
return value;
}
This call fails only under iOS arm64. arm7s and win32 work fine with this call. (Yes, our only 64 bit target platform is iOS arm64.)
In debugger I found that address of ptr in readInt function is different from what I got with:
void argPtr = va_arg(arg, void);
Am I working wrong with arg_list?
P.S. It is not a plain Objective C application. It is part of native Unity plugin. But in iOS Unity code is just transformed into Objective C/C++ from C#. That is why you can see second declaration:
extern "C" {int32_t CDECL ReadInfo(intptr_t, int32_t, int32_t*);}
It's not an issue of IL2CPP but an issue of iOS, or maybe the compiler.
The following code could reproduce the issue even on the latest Xcode (10.1) and iOS (12.1)
typedef int __cdecl (*PInvokeFunc) (const char*, int);
int test()
{
PInvokeFunc fp = (PInvokeFunc)printf;
fp("Hello World: %d", 10);
return 0;
}
The expected output is: Hello World: 10 but it will give Hello World: ??? (Random number) on iOS however.
I tried the same code on macOS and Linux and both of them work well.
I'm not sure if it relates to the Apple document or not:
Variadic Functions
The iOS ABI for functions that take a variable number of arguments is entirely different from the generic version.
Stages A and B of the generic procedure call standard are performed as usual—in particular, even variadic aggregates larger than 16 bytes are passed via a reference to temporary memory allocated by the caller. After that, the fixed arguments are allocated to registers and stack slots as usual in iOS.
The NSRN is then rounded up to the next multiple of 8 bytes, and each variadic argument is assigned to the appropriate number of 8-byte stack slots.
The C language requires arguments smaller than int to be promoted before a call, but beyond that, unused bytes on the stack are not specified by this ABI.
As a result of this change, the type va_list is an alias for char * rather than for the struct type specified in the generic PCS. It is also not in the std namespace when compiling C++ code.
https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html
Updates:
The reply for Apple engineer:
Casting function pointers to add a different calling convention doesn’t change how the callee is represented, it only changes how the caller performs its call. printf already has a calling convention, and what you’re doing might happen to work for some combinations on some platforms, while not working on others. You want to declare a wrapper function instead, which has the desired calling convention, and which calls the function you want. You’ll need to marshal the arguments manually.
That is to say the variadic function can't be direct p/invoke unless IL2CPP generate wrapper function for it. Only a function pointer is not enough.
The reason of this problem was in IL2CPP, which generates calls of function with variable argument. And it does not use my types like InfoType, myint64. It uses platform specific types for info variable. And size maybe different I guess.
I just add 3 new function for Unity API:
int32_t ReadInfoInt(void *handle, InfoType info, int *ret);
int32_t ReadInfoInt64(void *handle, InfoType info, myint64 *ret);
int32_t ReadInfoStr(void *handle, InfoType info, char **ret);
In this function I just call ReadInfo.
It is workaround 100%, but it is better then fight with IL2CPP.
My purpose is to call some C function from my C++ code and pass some C++ objects.
In fact I am using a integration routine from the GSL libray(written in C), see this link,
My code snippet:
// main.cpp
#include <stdio.h>
#include <gsl/gsl_integration.h>
#include <myclass.h>
/* my test function. */
double testfunction ( double x , void *param ) {
myclass *bar=static_cast<myclass*>(param);
/*** do something with x and bar***/
return val;
}
int main ( int argc , char *argv[] ) {
gsl_function F; // defined in GSL: double (* function) (double x, void * params)
/* initialize.*/
gsl_integration_cquad_workspace *ws =
gsl_integration_cquad_workspace_alloc( 200 ) ;
/* Prepare test function. */
myclass foo{}; // call myclass constructor
F.function = &testfunction;
F.params = &foo;
/* Call the routine. */
gsl_integration_cquad( &F, 0.0,1.0,1.0e-10,1.0e-10,ws, &res,&abserr,&neval);
/* Free the workspace. */
gsl_integration_cquad_workspace_free( ws );
return 0;
}
In my case, direct calling gsl_integration_cquad seems OK, provided the header includes sth like "ifdef __cplusplus", my concern is about the callback F,originally defined in C, am I allowed to pass the testfunction and also the C++ foo object in this way ? .
or is there any better way to do this kind of stuff, maybe overloading and use a functor?
P.S. Am I allowed to do exeption handling within the callback function? (use try catch inside "testfunction"). It works in my case but not sure if it's legal.
I'm not familiar with the library in question, but in general,
when passing a pointer to a callback and a void* to
a C routine, which will call the callback back with the void*,
there are two things you need to do to make it safe:
The function whose address you pass must be declared extern "C".
You'll get away with not doing this with a lot of compilers, but
it isn't legal, and a good compiler will complain.
The type you convert to the void* must be exactly the same
type as the type you cast it back to in the callback. The
classic error is to pass something like new Derived to the
C function, and cast it back to Base* in the callback. The
round trip Derived*→void*→Base* is undefined
behavior. It will work some of the time, but at other times, it
may crash, or cause any number of other problems.
And as cdhowie pointed out in a comment, you don't want to
allow exceptions to propagate accross the C code. Again, it
might work. But it might not.
For the exact example you posted, the only thing you need to do
is to declare testfunction as extern "C", and you're all
right. If you later start working with polymorphic objects,
however, beware of the second point.
You can use
myclass *bar=static_cast<myclass*>(param);
with void*.
If you meant something like transporting a c++ class pointer through a c callback's void* pointer, yes it's safe to do a static_cast<>.
There's no kind of losing c++ specific attributes of this class pointer, when passed through c code. Though passing a derived class pointer, and static casting back to the base class, won't work properly as #James Kanze pointed out.
The void* will likely just be passed trough by the C library without looking at the pointed-to data, so it's not a problem if this contains a C++ class. As log as you cast the void* to the correctly there shouldn't be any problems.
To make sure the callback function itself is compatible, you can declare it as extern "C". Additionally you should make sure that no exceptions are thrown from the callback function, since the C code calling the callback won't expect those.
All together I would split up the code into one function that does the real work and another function that is used as the callback and handles the interface with the C library, for example like this:
#include <math.h>
double testfunction ( double x ,myclass *param ) {
/*** do something with x and bar***/
return val;
}
extern "C" double testfunction_callback ( double x , void *param ) {
try {
myclass *bar=reinterpret_cast<myclass*>(param);
return testfunction(x, bar);
}
catch(...) {
std::cerr << "Noooo..." << std::endl;
return NAN;
}
}
I am writing an adapter to combine two APIs (one in C and another in C++).
If a function is called on the one API I need to pass the callers ID and the function's arguments to an adapter and call the according function with this information passed.
Now aparently they can not be mapped directly as one interface requires C++ compilation and the name mangling would screw the other so that is why I am using a set of adapters in the first place.
As the number of arguments varies, I looked up variadic functions and found the idea pretty useful, however I am operating on POD only and have to deal with structs, enums and a lot of different arguments per call, which might need to be put back into a struct before feeding it to the target function.
Every example I stumbled upon was far simpler and involved mostly arithmetic operations like summing stuff up , finding largest numbers or printing. Mostly done with for loops on the var_list.
Maybe I got stuck on the idea and it won't work at all, but I am just curious...
Say I wanted to assign the arguments from the list to my target functions parameters (the order of the arguments passed is the correct one), what would be a good way?
BOOL Some_Function(
/* in */ CallerId *pObjectId,
/* in */ someDataType argument1 )
{
BOOL ret = Adapter_Call(pFunction, pObjectId, argument1);
return ret;
}
and so once I made it to the right adapter I want to do
BOOL Adapter_Call(*pFunction, *pObjectId, argument1, ...)
{
va_list args;
va_start(args, argument1);
/*go over list and do `var_list[i] = pFunctionArgList[i]` which is
of whatever type so I can use it as input for my function */
va_end(args);
pObjectId.pFunction(arg1,...,argn);
}
Can I access the input parameters of a function to perform assignments like this?
Has anyone done something like this before? Is there a conceptual mistake in my thinking?
All I found on the net was this, http://www.drdobbs.com/cpp/extracting-function-parameter-and-return/240000586but due to the use of templates I am not sure if it wouldn't create another problem and so in the end implementing an adapter for each and every single functioncall may be simpler to do.
A SO search only returned this: Dynamic function calls at runtime (va_list)
First, you should heed Kerrek's advice about extern "C". This is C++'s mechanism for giving an identifier C linkage, meaning that the name won't be mangled by the C++ compiler.
Sometimes, and adapter still needs to be written for a C++ interface, because it manipulates objects that do not map to a C POD. So, the adapter gives the C interface a POD or opaque pointer type to manipulate, but the implementation of that interface converts that into an C++ object or reference and then calls the C++ interface. For example, suppose you wanted to provide a C interface for C++ std::map<int, void *>, you would have a common header file in C and C++ that would contain:
#ifdef __cplusplus
extern "C" {
#endif
struct c_map_int_ptr;
// ...
// return -1 on failure, otherwise 0, and *data is populated with result
int c_map_int_ptr_find (struct c_map_int_ptr *, int key, void **data);
#ifdef __cplusplus
}
#endif
Then, the C++ code could implement the function like:
typedef std::map<int, void *> map_int_ptr;
int c_map_int_ptr_find (struct c_map_int_ptr *cmap, int key, void **data) {
map_int_ptr &map = *static_cast<map_int_ptr *>(cmap);
map_int_ptr::iterator i = map.find(key);
if (i != map.end()) {
*data = i->second;
return 0;
}
return -1;
}
Thus, there is no need to pass the arguments passed via the C interface through a variable argument adapter. And so, there is no need for the C++ code to tease out the arguments from a variable argument list. The C code calls directly into the C++ code, which knows what to do with the arguments.
I suppose if you are trying to implement some kind of automated C adapter code generator by parsing C++ code, you could think that using variable arguments would provide a regular mechanism to communicate arguments between the generated C code interface and the generated C++ adapter code that would call the original C++ interface. For such a scenario, the code for the above example would look something like this:
// C interface
typedef struct c_map_int_ptr c_map_int_ptr;
typedef struct c_map_int_ptr_iterator c_map_int_ptr_iterator;
//...
c_map_int_ptr_iterator c_map_int_ptr_find (c_map_int_ptr *map, int key) {
c_map_int_ptr_iterator result;
cpp_map_int_ptr_adapter(__func__, map, key, &result);
return result;
}
// C++ code:
struct cpp_adapter {
virtual ~cpp_adapter () {}
virtual void execute (va_list) {}
};
void cpp_map_int_ptr_adapter(const char *func, ...) {
va_list ap;
va_start(ap, func);
cpp_map_int_ptr_adapter_method_lookup(func).execute(ap);
va_end(ap);
}
//...
struct cpp_map_int_ptr_find_adapter : cpp_adapter {
void execute (va_list ap) {
map_int_ptr *map = va_arg(ap, map_int_ptr *);
int key = va_arg(ap, int);
c_map_int_ptr_iterator *c_iter = va_arg(ap, c_map_int_ptr_iterator *);
map_int_ptr::iterator i = map->find(key);
//...transfer result to c_iter
}
};
Where cpp_map_int_ptr_adapter_method_lookup() returns an appropriate cpp_adapter instance based on a table lookup.
I'm a little confused about how to pass an object to the pthread_create function. I've found a lot of piecemeal information concerning casting to void*, passing arguments to pthread_create, etc., but nothing that ties it all together. I just want to make sure I've tied it all together and am not doing anything stupid. Let's say I have the following thread class:
Edit: fixed mis-matched static_cast.
class ProducerThread {
pthread_t thread;
pthread_attr_t thread_attr;
ProducerThread(const ProducerThread& x);
ProducerThread& operator= (const ProducerThread& x);
virtual void *thread_routine(void *arg) {
ProtectedBuffer<int> *buffer = static_cast<ProtectedBuffer<int> *> arg;
int randomdata;
while(1) {
randomdata = RandomDataGen();
buffer->push_back(randomdata);
}
pthread_exit();
}
public:
ProtectedBuffer<int> buffer;
ProducerThread() {
int err_chk;
pthread_attr_init(&thread_attr);
pthread_attr_setdetachstate(&thread_attr,PTHREAD_CREATE_DETACHED);
err_chk = pthread_create(&thread, &thread_attr, thread_routine, static_cast<void *> arg);
if (err_chk != 0) {
throw ThreadException(err_chk);
}
}
~ProducerThread() {
pthread_cancel(&thread);
pthread_attr_destroy(&thread_attr);
}
}
To clarify, the data in the ProtectedBuffer class can only be accessed with methods like ProtectedBuffer::push_back(int arg), which use mutexes to protect the actual data.
My main question is: am I using static_cast correctly? And my secondary question is do I need that first line in virtual void *thread_routine(void *arg) where I copy the passed void pointer to a pointer to ProtectedBuffer?
Also, if I've done anything else that might cause problems, I'd appreciate hearing it.
There are a number of problems with your code. For starters, I don't
see where the arg you are casting is declared, so I can't say whether
the case is appropriate.
Perhaps more importantly, thread_routine is a member function, so it
can't be converted to a pointer to a function. The function passed to
pthread_create must be extern "C", so it cannot be a member, period;
it must be a free function declare extern "C". If you want to call a
member function, pass a pointer to the object as the last argument, and
dereference it in the extern "C" function:
extern "C" void* startProducerThread( void* arg )
{
return static_cast<ProducerThread*>( arg )->thread_routine();
}
And to start the thread:
int status = pthread_create( &thread, &thread_attr, startProducerThread, this );
Just don't do this in a constructor. The other thread might start
running before the object is fully constructed, with disasterous
effects.
Also, be very sure that the cast in startProducerThread is to
exactly the same type as the pointer passed into pthread_create. If
you cast to a base class in startProducerThread, then be very, very
sure that it is a pointer to that base class that you pass to
pthread_create; use an explicit cast if necessary (to the type in
startProducerThread, not to void*).
Finally, while not relevant to your actual question: if
ProtectedBuffer has an interface like that of std::vector, and
returns references to internal data, there's no way you can make it
thread safe. The protection needs to be external to the class.
If you want to go this route, I believe you want something like this:
Edit: Based on James Kanze's answer, add a separate activate method to launch the thread after construction is finished.
class GenericThread {
protected:
GenericThread () {
//...
}
virtual ~GenericThread () {}
int activate () {
return pthread_create(..., GenericThreadEntry, this);
}
virtual void * thread_routine () = 0;
#if 0
// This code is wrong, because the C routine callback will do so using the
// C ABI, but there is no guarantee that the C++ ABI for static class methods
// is the same as the C ABI.
static void * thread_entry (void *arg) {
GenericThread *t = static_cast<GenericThread *>(arg);
return t->thread_routine();
}
#endif
};
extern "C" void * GenericThreadEntry (void *) {
GenericThread *t = static_cast<GenericThread *>(arg);
return t->thread_routine();
}
Then, ProducerThread would derive from GenericThread.
Edit: Searching for extern "C" in the C++ Standard. revealed no requirement that a function pointer must point to a function with C linkage to be callable by a C library routine. Since pointers are being passed, linkage requirements do not apply, as linkage is used to resolve names. A pointer to a static method is a function pointer, according to C++ 2011 draft (n3242), Sec. 3.9.2p3:
Except for pointers to static members, text referring to pointers does not apply to pointers to members.
Edit: Mea culpa. The C library will invoke the callback function assuming the C application binary interface. A function with C++ linkage may use a different ABI than the C ABI. This is why it is required to use a function with extern "C" linkage when passing to a callback function to a C library. My sincere apologies to James Kanze for doubting him, and my sincere thanks to Loki Astari for setting me straignt.