Willem said:
Keith Thompson wrote:
) If you use a cast, compilers tend to assume you know what you're doing
) and shut up. But you're still invoking undefined behavior.
)
) cb is declared as a pointer to a function returning void. You're
) converting it (with a cast) to a pointer to a function returning a
) pointer to a function returning void, and then doing a function call
) via the converted function pointer. Calling a function using a type
) other than the actual type of the function invokes UB.
Anyway, I don't think it's UB because the function pointer gets
converted to another type, and then back to the original type.
Perhaps I missed something among the masses of parentheses, but
I don't see a conversion back to the original type.
Here's the code in question:
| typedef void (*fp)();
|
| void run()
| {
| fp cb;
|
| cb = init;
| for (;
| cb = ((fp (*)())cb)();
| }
Now that I think about it, we haven't seen a declaration for init.
If init is either a function returning fp, or a pointer to such a
function, it might be ok.
I was under the impression that the same held for void pointers.
(I.E. converting to void pointer and then back to the original
function pointer type would be conormant.)
No, conversion between pointer-to-void and pointer-to-function is not
guaranteed to be meaningful. (Some real-world systems have function
pointers that are much bigger than void* pointers, so such conversions
could lose information.)
If not, how can a function return a pointer to itself without
invoking UB ? Preferrably without some horrid convoluted syntax ?
It can't directly return a pointer to itself, but you can pick an
arbitrary function type to be used as a generic function type, and
explicitly convert back and forth between the generic type and
whatever type you need. I'd use something like:
typedef void generic_function(void);
though some might prefer to typedef the pointer-to-function type
rather than the function type.
If the actual defined functions return pointers to fp, then the code
in question may be correct. Though I'd prefer not to use empty
parentheses, denoting an old-style function declaration with
unspecified parameters. In other words, I'd write:
typedef void (*fp)(void);
rather than
typedef void (*fp)();