Pass function pointer to xTaskCreate with void* pvParameters - c++

Is it possible to pass a function pointer as the parameter for the freeRTOS xTaskCreate function?
I suspect I need to cast the void* pvParameters within the task before I can call it but I am not sure what such as cast would be.
class param
{
private:
//Initialized during construction to hardware specific value.
uint8_t mParam = 0;
public:
uint_8 getParam() {return mParam;}
};
void task(void* pvParameters)
{
//get hardware specific pvParameters.
uint8_t hwParam = pvParameters();
// Do task things.
}
main()
{
param p;
uint32_t result;
result = xTaskCreate(task, "Task", configMINIMAL_STACK_SIZE, (void *)&p.getParam, configMAX_PRIORITIES - 1, nullptr); //lint !e712 implicit conversion from long to int
if (result == 0)
{
//print error msg.
}
else
{
vTaskStartScheduler();
for(;;) {ASM("NOP");}
}
}

Why not using &p (address of object p) as argument to access the complete param object using a cast like this:
param& p = *(param*)pvParameters;
Beware that for a number of ports/MCUs the main stack is reused as ISR stack and main stack allocated arguments might get corrupted. Better use e.g. static/new param object.

Related

How do I cast int** to void**?

With the following snippet:
int n = 11;
int* c = &n;
void** v = &c;
I receive the following error in visual studio:
the value of type int** cannot be used to initialize an entity of type void **.
This works fine:
int n = 11;
int* c = &n;
void* v = c;
But this code snippet is for a larger problem in someone's library.
What am I doing wrong with casting a variable to void**?
Complete Example
Using the caen digitizer library the way they try to collect data from the peripheral device has this prototype:
/******************************************************************************
* X742_DecodeEvent(char *evtPtr, void **Evt)
* Decodes a specified event stored in the acquisition buffer writing data in Evt memory
* Once used the Evt memory MUST be deallocated by the caller!
*
* [IN] EventPtr : pointer to the requested event in the acquisition buffer (MUST BE NULL)
* [OUT] Evt : event structure with the requested event data
* : return 0 = Success;
******************************************************************************/
int32_t X742_DecodeEvent(char *evtPtr, void **Evt);
And this is the implementation:
int32_t X742_DecodeEvent(char *evtPtr, void **Evt) {
CAEN_DGTZ_X742_EVENT_t *Event;
uint32_t *buffer;
char chanMask;
uint32_t j,g,size;
uint32_t *pbuffer;
uint32_t eventSize;
int evtSize,h;
evtSize = *(long *)evtPtr & 0x0FFFFFFF;
chanMask = *(long *)(evtPtr+4) & 0x0000000F;
evtPtr += EVENT_HEADER_SIZE;
buffer = (uint32_t *) evtPtr;
pbuffer = (uint32_t *) evtPtr;
eventSize = (evtSize * 4) - EVENT_HEADER_SIZE;
if (eventSize == 0) return -1;
Event = (CAEN_DGTZ_X742_EVENT_t *) malloc(sizeof(CAEN_DGTZ_X742_EVENT_t));
if (Event == NULL) return -1;
memset( Event, 0, sizeof(CAEN_DGTZ_X742_EVENT_t));
for (g=0; g<X742_MAX_GROUPS; g++) {
if ((chanMask >> g) & 0x1) {
for (j=0; j<MAX_X742_CHANNEL_SIZE; j++) {
Event->DataGroup[g].DataChannel[j]= malloc(X742_FIXED_SIZE * sizeof (float));
if (Event->DataGroup[g].DataChannel[j] == NULL) {
for (h=j-1;h>-1;h++) free(Event->DataGroup[g].DataChannel[h]);
return -1;
}
}
size=V1742UnpackEventGroup(g,pbuffer,&(Event->DataGroup[g]));
pbuffer+=size;
Event->GrPresent[g] = 1;
}
else {
Event->GrPresent[g] = 0;
for (j=0; j<MAX_X742_CHANNEL_SIZE; j++) {
Event->DataGroup[g].DataChannel[j] = NULL;
}
}
}
*Evt = Event;
return 0;
}
I use this by:
CAEN_DGTZ_X742_EVENT_t* Evt = NULL; // Creating my event pointer
//Doing some config of the device
X742_DecodeEvent(evtptr, &Evt); //Decode the event data for me to read (Throws error)
Hope this gives some context.
void** means a pointer to a void* object. But there is no void* object in that code to point at! void** does NOT mean "a pointer to any kind of pointer", so please avoid using it as such. If you have a pointer to something which might be an int*, might be a double*, or etc., void* is a better type than void**. Even better would be a template or std::variant or std::any.
But if you have to use a library that is using void** to mean "a pointer to a pointer to a type unknown at compile time" or something like that, you might need to create a void* pointer to work with, or might need to add in casts to get around the fact that the compiler doesn't like this conversion (for good reason). The problem is, there are at least two reasonable ways to do this! (They will end up doing exactly the same thing on many common computer architectures, but this is not guaranteed.)
// LibraryFunc1 takes a void** argument that somehow means an int* pointer.
// But which call is correct?
int* data_in = generate_data();
LibraryFunc1(reinterpret_cast<void**>(&data_in)); // ?
void* p1 = data_in;
LibraryFunc1(&p1); // ?
// LibraryFunc2 returns a void** argument that somehow means an int* pointer.
void** p2 = LibraryFunc2();
int* data_out_1 = static_cast<int*>(*p2); // ?
int* data_out_2 = *reinterpret_cast<int**>(p2); // ?
Based on the function definition shown, the safe usage is unfortunately:
void* tmpEvt;
X742_DecodeEvent(evtptr, &tmpEvt);
auto* Evt = static_cast<CAEN_DGTZ_X742_EVENT_t*>(tmpEvt);
since the library function assumes at *Evt = Event; that *Evt is actually a void* object it can modify. It may usually work to do the simpler thing instead:
CAEN_DGTZ_X742_EVENT_t* Evt = NULL;
X742_DecodeEvent(evtptr, reinterpret_cast<void**>(&Evt));
but this is undefined behavior by the C++ Standard, and might do the wrong thing on some architectures.
You could make the correct way easier by wrapping it in a function:
inline CAEN_DGTZ_X742_EVENT_t* Get_X742_DecodeEvent(char* evtPtr)
{
void* tmpEvt;
X742_DecodeEvent(evtPtr, &tmpEvt);
return static_cast<CAEN_DGTZ_X742_EVENT_t*>(tmpEvt);
}
What am I doing wrong with casting a variable to void**?
There is no meaningful way to convert int** to void**, so what you're trying to do is wrong.
What you may do is
int n = 11;
void* c = &n;
void** v = &c;
But without a complete example, it is not possible to say whether applies to your problem.
That's simply how the language works.
void * pointers get special treatment: a pointer to an arbitrary type can be converted to a pointer to void (as long as doing so doesn't remove cv-qualifiers from the pointer).
void ** gets none of that special treatment. It's just a regular pointer type, like int **.
int32_t X742_DecodeEvent(char *evtPtr, void **Evt)
Since you want to pass CAEN_DGTZ_X742_EVENT_t ** to your function, you should change the parameter type accordingly: CAEN_DGTZ_X742_EVENT_t **Evt.
In comments you were suggested to use void ** v = (void**)&c;.
While you could probably make it work in practice, strictly speaking any access to *v would violate strict aliasing and cause undefined behavior. I wouldn't use that solution.

Pass object pointer via char[] to callback

I have this function callback that receives a param of type T. T has a member function, GetData(), defined as below, which returns data to be used within the callback:
void Callback(T* t) {
int64_t val;
auto data = t->GetData();
memcpy(&val, data, 8);
std::cout << "Value: " << val;
}
// Member of a class T:
char mData[64];
// Member functions of T
const char* GetData() const { return mData; }
void SetData(void* data, uint8_t size) {
if (size > 0) {
memcpy(mData, data, size);
}
}
The above works fine. However, for some reason, I can't seem to pass a 'this' pointer of a class within the data component. This is how the data is copied to the mData member.
// This works
char data[64];
int64_t val = 42;
memcpy(&data, &val, 8);
t->SetData(data, 8);
// For storing 'this', I tried variations of the below.
char data[64];
memcpy(&data, this, 8);
t->SetData(data, 8);
// t->SetData(this, 8);
When I try to store 'this' in the data, and then try to get it back in the callback, I can't seem to get the this pointer's value correctly. I tried variations of the below, including reinterpret_cast and others.
void Callback(T* t) {
TypeOfThis* self;
auto data = t->GetData();
memcpy(&self, data, 8);
// self has bogus values.
}
How can I pass a 'this' pointer correctly, in the case above?
firstly "this" is to be used inside a class. 2ndly: "this" address does not necessarily point to the first data member of the class as there are some admin data subject to the compiler implementation, in other words there may be a few bytes gap between "this" and its first data member.

ESP was not properly saved across a function call when using function pointers

I am trying to create a program which saves the function pointer of a member function to an array. The program then takes the function pointer from that array and calls the function said pointer points to. This works as long as the member function used does not have any arguments. When I give it arguments the following error occurs in Visual Studio 2017:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
My code is:
typedef uint8_t byte;
template<typename T>
class Test
{
public:
void FuncTest(byte* data)
{
cout << (T)(0.0625f) << endl;
}
};
typedef Test<float> fTest;
typedef Test<long long> lTest;
int main()
{
byte data[1024];
{
void (fTest::*ffp)(byte*) = &fTest::FuncTest;
//void (lTest::*lfp)(byte*) = &lTest::FuncTest;
printf("%p\n", ffp);
memcpy(&data[0], (int64*)&ffp, sizeof(int64));
}
{
int64 pData;
memcpy(&pData, &data[0], sizeof(int64));
void(*func_pointer)(byte*) = (void(*) (byte*))(pData);
printf("%p\n", pData);
func_pointer(nullptr);
}
}
If anyone could help, it would be greatly appreciated.
Ignoring the storage in an array your code is essentially:
void (Test::*ffp)(byte*) = &fTest::FuncTest;
void* pData = (void*)ffp;
void(*func_pointer)(byte*) = (void(*) (byte*))(pData);
func_pointer(nullptr);
The type of ffp is essentially (although not exactly due to differing calling conventions) void (fTest*, byte*) which doesn't match the type of func_pointer.
The solution to this is to use std::function with with either std::bind or lambdas to convert the function signatures. e.g.:
std::vector<std::function<void(byte*)>> functions;
fTest test;
functions.push_back([=](byte* data){ test.FuncTest(data); });
functions.front()(nullptr);

C/C++ How to hand over a const function pointer or a simple pointer in one function call

I have a function (func1) that gets as a parameter a const pointer.
The value of this pointer is used for a second function (func2).
Depending on a boolean I want to modify this value before handing it to func2 or not. If I have to modify it I allocate new memory to store the modified version of it. Because in reality the const int pointer is a big array, I don't want to copy it.
I tried to solve it that way:
void func1(const int* value, bool change)
{
int* valueToUse;
if(change)
{
int changedValue = (*value)++;
valueToUse = &changedValue;
}
else
{
valueToUse = value; // <= here the Error occurs
}
func2(valueToUse);
}
void func2(const int* foo)
{
// ...
}
But if I do it this way, I get an error because I assign a const pointer to a simple pointer:
error: invalid conversion from 'const int* to int*'
Is there any easy way to solve this?
I can imagine a solution with two extra functions for each case or a version that calls func2 at two points. But because this presented code is only a very simplified version of my real code, I'm wandering if there is an easier solution to that.
Best would be a solution that works for C and C++.
Thanks guys in advance!
This works?
void func1(const int* value, bool change)
{
const int* valueToUse;
int changedValue;
if(change)
{
changedValue = (*value) + 1;
valueToUse = &changedValue;
}
else
{
valueToUse = value;
}
func2(valueToUse);
}
A const int* is a pointer to const int, which is not a const pointer to int. Therefore the pointer itself is free to change.
Also, incrementing (*value) is an error because *value is a const int.
In func1, you can make 2 calls to func2, this way there is no copy when not needed and the original value is never changed:
void func1(const int* value, bool change)
{
if(change)
{
int changedValue = *value+1;
func2(&changedValue);
}
else
{
func2(value);
}
}
void func1(const int* value, int change)
{
int* valueToUse;
if(change)
{
(*(int*)value)++;
valueToUse = (int*)value;
}
else
{
valueToUse = (int*)value; // <= here the Error occurs
}
func2(valueToUse);
}
But you don't really need this valueToUse, it's what i think, so.
void func1(const int* value, int change)
{
if(change)
(*(int*)value)++;
func2(value);
}
const int* value
This means pointer to a constant int value. It is not permitted to change the value of a constant int.
There are two ways of solving this.
Change signature of first function void func1(int* value, bool change)
Pass arguments to func1 after constant casting using const_cast and change
int changedValue = (*value)++; to int changedValue = *value + 1;
Well, running this code i receive just a warning, though i think that type conversion will help you.
valueToUse = (int*)value;

Callback functions with different arguments

I have two functions with a little different functionality, so I can't make them as template functions.
int func64(__int64 a) {
return (int) a/2;
}
int func32(int a) {
return a--;
}
Depending on variable b64, I would like to call func64 or func32. I don't want check if b64 is true many times in my code, so I use pointers to functions.
void do_func(bool b64) {
typedef int (*pfunc32)(int);
typedef int (*pfunc64)(__int64);
pfunc32 call_func;
if (b64)
call_func = func64; //error C2440: '=' : cannot convert from 'int (__cdecl *)(__int64)' to 'pfunc32'
else
call_func = func32;
//...
call_func(6);
}
How can I avoid this error and cast call_func to pfunc32 or pfunc64?
The language requires all functions called through the same function pointer to have the same prototype.
Depending on what you want to achieve, you could use the pointer/cast aproach already mentioned (which satisfies this requirement at the loss of type safety) or pass a union instead:
union u32_64
{
__int64 i64;
int i32;
};
int func64(union u32_64 a) {
return (int) a.i64/2;
}
int func32(union u32_64 a) {
return --a.i32;
}
void do_func(bool b64) {
typedef int (*pfunc)(union u32_64);
pfunc call_func;
if (b64)
call_func = func64;
else
call_func = func32;
//...
union u32_64 u = { .i64 = 6 };
call_func(u);
}
Pass a void pointer and cast it in the function body.
Of course this means less compiler control if you use the wrong type; if you call func64 and pass an int to it the program will compile and produce wrong results without giving you any tip of what is going wrong.
int func64(void *a) {
__int64 b = *((__int64*) a);
return (int) b/2;
}
int func32(void *a) {
int b = *((int *) a)
return b-1;
}
I need to call func32() or func64() depending on flag b64
So do that:
void do_func(bool b64) {
if (b64)
func64(6);
else
func32(6);
}
Well, first of all, please note that function func32 is returning the input argument as is.
This is because with return a--, you are returning the value of a before decrementing it.
Perhaps you meant to return a-1 instead?
In any case, you can simply declare this function as int func32(__int64 a).
This way, it will have the same prototype as function func64, but will work exactly as before.
BTW, calling a function through a pointer might be more "expensive" than a simple branch operation, so depending on your application, you might be better off with a simple if/else conditional statement...
Make a wrapper for func64:
int func64_as_32(int a) {
return func64(a);
}
Now you can assign either func32 or func64_as_32 to call_func since they have the same signature. The value you pass in, 6, has type int so passing it to func64_as_32 has the same effect as passing it directly to func64.
If you have call sites where you pass in a value of type __int64 then you'd do it the other way around, wrap func32.
As bool in C++ converts to int ( true => 1, false => 0 ) you can use b64 as array index. So take SJuan76's advice, convert your functions prototype to int f(void*) and put them into array int (*array_fun[2])(void* x); . You can call these functions then like that :
int p = 6;
array_fun[b64](&p);