Casting function pointers

I wonder how casting with function pointers work, how it "should be" handled and how it "should not be" handled. Can anyone tell whether the below code should work or not?

Module: Task Service Abstraction Layer int taskCreate(char* taskName, void* funcPtr, int taskPriority,..........) { myTaskStructure TaskProperties; int TaskId, errStatus;

............ //Casting void* funcPtr to function pointer that returns void and accepts no arguments TaskProperties.entryPtr = (void ()(void)* ) funcPtr; errStatus = rtosTaskCreate( taskName, &TaskProperties, &TaskId);

......... }

Module: SomeClass.cpp

void someClass::taskLoop( int taskArgument) { ....... }

void somClass::initialize( void ) {

taskCreate( "Task1", (void* )&taskLoop, 25,.....); }

Module: SomeOtherClass.cpp

int myTaskEntryReturnsInt( void ) {

}

SomeOtherClass::initialize( void ) { taskCreate( "Task2", (void* )&myTaskEntryReturnsInt, 30,.....); }

Module: AnotherClass.cpp void myTaskEntryTakesInt( int TaskArg ) {

}

AnotherClass::initialize( void ) { taskCreate( "Task3", (void* )&myTaskEntryTakesInt, 40,.....); }

My question is whether these kind of casting for function pointers is valid. If valid should it work with a predictable behavior or the behavior is undefined.

Reply to
KKL
Loading thread data ...

Why ?

The example makes no sense. If your task mechanism doesn't support tasks returning/accepting any kind of value, then why bother declaring your task entries as functions that do so ?

Just declare your task entries as

void myTaskEntry( void )

And use:

int taskCreate(char* taskName, void (*funcPtr)( void), ...

No casts are required that way, and the compiler will be able to verify pointer types for you.

Reply to
Arlet

No it is not. There is plenty of mistakes in your example. The first one: you can't cast a class member function to an ordinary function.

Vladimir Vassilevsky DSP and Mixed Signal Design Consultant

formatting link

Reply to
Vladimir Vassilevsky
[example casting various member functions to task functions snipped]

1) You have to pass a compatible function pointer to the "TaskCreate" function. Frequently this will be "void TaskType(void *arg)" or something like "int TaskType(void *arg)". Some OSes might have additional parameters but generally void * is enough. You generally can't cast a function pointer to a different one, especially if the argument list is different, since the stack will probably get misaligned or the arguemnts will get passed in the wrong registers.

2) Member functions in C++ take the hidden "this" point argument so you can never pass them to general "TaskCreate" type functions unless the OS knows about the base class of your class.

What I usually do is this:

class ActiveClass { protected: static void ThreadStarter(void *arg) { ((ActiveClass

*)arg)->ThreadProc(); } void ThreadProc() { while (1) { DoTaskStuff(); } }

public: int Start() { TaskCreate(ThreadStarter, this); } // assumption: second argument is what's passed to "arg" };

The important thing is that ThreadStarter is static, which turns it into a normal non-member function and that arg is cast to the type of the class that has the member function with the task handling.

There are various ways of generalizing this approach with templates. You can also pull out the ThreadStarter into a function outside of the class but I like bundling things together as shown.

Andrew

Reply to
andrew queisser

That's actually quite simply: it "should not" be handled at all.

Whenever you think you should cast a function pointer, the probability is very high that you're trying to do the wrong thing, so it's generally best to not do it at all.

The only safe casts involving function pointers are those to other function pointer types --- and that only if you cast back to the original type before actually using the pointer to call the function. But if you must eventually go back to the original type anyway, what would be the point of casting in the first place?

This is an invitation for disaster. Function pointers and data pointers don't mix. Not even if the data pointers are (void *).

And on top of that, your function pointer cast looks syntactically wrong. It should be (void (*)(void)).

Reply to
Hans-Bernhard Bröker

Le Wed, 30 Jan 2008 10:46:26 -0800, KKL a écrit:

(void ()(void)* ) funcPtr does not make any sense.

Is your code compiles ? No offense, If so i wish you good luck (and therefore to those who work with you)

--
HBV
Reply to
Habib Bouaziz-Viallet

with data pointers - you can't

valid result (although it should work

pointer to a function pointer (unless

Correct. Both pointer to member and pointer to method typically have a completely different meaning and representation to normal pointers, including a different bitpattern to represent the null pointer (the 0 value is already used for offset 0 or the first virtual function). Since there is a lot more complexity in C++, different C++ compilers all do something different (and binary incompatible) - except when adhering to a common ABI.

C function pointers and data pointers are best not mixed.

Wilco

Reply to
Wilco Dijkstra

It's also important to note that function pointers are not directly compatible with data pointers - you can't necessarily convert a function pointer to a void* and back again, and expect a valid result (although it should work in practice, at least on 32-bit processors). You can't ever convert a method pointer to a function pointer (unless it's a static method).

Personally, I think phrases such as "(void ()(void)* ) funcPtr" are ugly and hard to read. Use typedefs - they make your code clearer, minimise mistakes, and make it easier to change later:

typedef void (*FVoid)(void);

int taskCreate(char* taskName, FVoid funcPtr, ....)

Reply to
David Brown

Hi Habib,

I am a new use to the group and did not know that putting code snippets that do not compile is such a serious offense even if you are discussing here some logical issues here and not syntactical ones.

Ok, so I accept my offense that the code snippets have syntactical issues and that is because I did not simply copy it from my C source files but just wrote it in hurry to put up an example for my point of discussion which was "IS TYPE CASTING FUNCTION POINTERS FROM void (*) (int) TO (void *) AND BACK TO void (*)(void) AND THEN USING IT TO CALL FUNCTIONS IS A VALID AND SAFE OPERATION OR NOT".

And regarding your comment about Good luck to those that work with me, may be you don't know that if making logical mistakes costs you much more than making syntactical mistakes and those mistakes are mostly done by people who stresses more on syntax rather than the actual thing which is LOGIC. So a good luck is required more to people who miss the whole point and and try hard to prove their knowledge stressing on the syntax (since that itself is hard thing for them).

So, now I think you know what it means to take offense.

Regards

Reply to
KKL

According to the C99 standard, paragraph 6.3.2.3p8:

"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."

In other words, it is safe to convert them, as long as you convert them back to the original type before calling the function. If you call them as a different type, the behavior is undefined (potentially crashing your program)

Reply to
Arlet Ottens

Le Thu, 31 Jan 2008 10:35:11 -0800, KKL a écrit:

Hi KKL !

Is there a real difference between a clear mind and a clear syntax? The clear syntax reveals a clear thought. It is believed that the often obscure code is effective but most of the time it is not.

I agrre with you, the logical errors are those that cost the most and therefore there is no need to add syntax errors.

Yes.

Best regards KKL,

--
HBV
Reply to
Habib Bouaziz-Viallet

He posted C++ code IIRC, so that standard does not apply.

--
Stef    (remove caps, dashes and .invalid from e-mail address to reply by mail)
Reply to
Stef

There is a huge huge difference between a clear mind and clear syntax. Any automation tool can generate clear syntax and any compiler can tell syntax mistakes and corrections, so do you conclude that tool have a better mind (the thought power ) to write programs.

Look at my code the dots dots dots "............" , are all around, including the function defintions and calls. Why on earth would you think that the code was meant to compile. It was meant to discuss a point that I have already explained.

So, I would sugest you to restrain from making such comments as "Good luck to those who work with you", A person who can see the roots (the underlying points) (with an actual clear mind) only has the right to make judgements.

May be you are right here. The thoughtful people with clear mind would never let the compiler do their job of complaining about the syntax.Since if it does then it will prove that compiler has clearer mind than us and how is that possible.

Reply to
KKL

Le Fri, 01 Feb 2008 06:23:13 -0800, KKL a écrit:

You forgot i mention "no offense". Would you be so kind to agree my apologies.

Best regards, Habib

--
HBV
Reply to
Habib Bouaziz-Viallet

Oops, I took it too seriously, as I was hurt.

Regards & Apologies KKL

Reply to
KKL

The first rule of casting is: don't. In particular for function pointers, if they don't compile, they won't run. If they only compile after casting, they won't run.

If you have to ask the question, about how, instead of having studied the assembler code the compiler generates, you shouldn't use casting. Casting is a very rude remark to the compiler: "Shut up! *I* know better!"

Your first priority is to get your code past the compiler, without casting. There is no guarantee that it will run then, but at least you stand a chance.

Groetjes Albert.

--

--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- like all pyramid schemes -- ultimately falters.
 Click to see the full signature
Reply to
Albert van der Horst

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.