Why can't I cast a function pointer to (void *)? - c

I have a function that takes a string, an array of strings, and an array of pointers, and looks for the string in the array of strings, and returns the corresponding pointer from the array of pointers. Since I use this for several different things, the pointer array is declared as an array of (void *), and the caller should know what kind of pointers are actually there (and hence what kind of a pointer it gets back as the return value).
When I pass in an array of function pointers, however, I get a warning when I compile with -Wpedantic:
clang:
test.c:40:8: warning: assigning to 'voidfunc' (aka 'void (*)(void)') from 'void *' converts
between void pointer and function pointer [-Wpedantic]
gcc:
test.c:40:8: warning: ISO C forbids assignment between function pointer and ‘void *’ [-Wpedantic]
fptr = find_ptr("quux", name_list, (void **)ptr_list,
Here's a test file, which despite the warning does correctly print "quux":
#include <stdio.h>
#include <string.h>
void foo(void)
{
puts("foo");
}
void bar(void)
{
puts("bar");
}
void quux(void)
{
puts("quux");
}
typedef void (* voidfunc)(void);
voidfunc ptr_list[] = {foo, bar, quux};
char *name_list[] = {"foo", "bar", "quux"};
void *find_ptr(char *name, char *names[], void *ptrs[], int length)
{
int i;
for (i = 0; i < length; i++) {
if (strcmp(name, names[i]) == 0) {
return ptrs[i];
}
}
return NULL;
}
int main() {
voidfunc fptr;
fptr = find_ptr("quux", name_list, (void **)ptr_list,
sizeof(ptr_list) / sizeof(ptr_list[0]));
fptr();
return 0;
}
Is there any way to fix the warning, other than not compiling with -Wpedantic, or duplicating my find_ptr function, once for function pointers and once for non-function pointers? Is there a better way to achieve what I'm trying to do?

You can't fix the warning. In fact, in my opinion it should be a hard error since it's illegal to cast function pointers to other pointers because there are architectures out there today where this isn't just a violation of the C standard but an actual error that will make the code not work. Compilers allow it because many architectures get away with it even though those programs will crash badly on some other architectures. But it's not just a theoretical standard violation, it's something that causes real bugs.
For example on ia64 function pointers are (or at least used to be last time I looked) actually two values, both necessary to make function calls across shared libraries or a program and a shared library. Likewise, the common practice to cast and call function pointers to functions returning a value to a pointer to a function returning void because you know you'll ignore the return value anyway is also illegal on ia64 because that can lead to trap values leaking into registers causing crashes in some unrelated piece of code many instructions later.
Don't cast function pointers. Always have them match types. This is not just standards pedantry, it's an important best practice.

One solution is to add a level of indirection. This helps with lots of things. Instead of storing a pointer to a function, store a pointer to a struct storing a pointer to a function.
typedef struct
{
void (*ptr)(void);
} Func;
Func vf = { voidfunc };
ptrlist[123] = &vf;
etc.

This is something that has long been broken in the C standard and has never been fixed -- there is no generic pointer type that can be used for pointers to functions and pointers to data.
Before the C89 standard, all C compilers allowed converting between pointers of different types, and char * was generally used as a generic pointer that might point to any data type or any function. C89 added void *, but put in a clause that only object pointers could be converted to void *, without ever defining what an object is. The POSIX standard fixes this issue by mandating that void * and function pointers are safely convertable back and forth. So much code exists that converts function pointers to void * and expects it to work properly. As a result, pretty much all C compilers still allow it, and still generate the correct code, as any compiler that did not would be rejected as unusable.
Strictly speaking, if you want to have a generic pointer in C, you need to define a union that can hold either a void * or a void (*)() and use an explicit cast of the function pointer to the correct function pointer type before calling it.

The language lawyering reason is "because C standard does not explicitly allow it." C11 6.3.2.3p1/p8
1. A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a
pointer to void and back again; the result shall compare equal to the
original pointer.
8. 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 referenced
type, the behavior is undefined.
Notice that a function is not an object in C terminology, hence there is nothing that allows you to convert a pointer to a function to a pointer to void, hence the behaviour is undefined.
Castability to void * is a common extension though. C11 J.5 Common extensions 7:
J.5.7 Function pointer casts
1. A pointer to an object or to void may be cast to a pointer to a function, allowing data to be invoked as a function (6.5.4).
2. A pointer to a function may be cast to a pointer to an object or to void, allowing a function to be inspected or modified (for example, by a debugger) (6.5.4).
This is required by for example POSIX - POSIX has a function dlsym that returns void * but in fact it returns either a pointer to a function or a pointer to an object, depending of the type of the symbol resolved.
As to why this happens - nothing in C standard is undefined or unspecified if the implementations could agree on it. However there were and are platforms where the assumption that a void pointer and function pointer would be of the same width would really make things difficult. One of these is the 8086 16-bit real mode.
And what to use instead then? You can still cast any function pointer to another function pointer, so you can use a generic function pointer void (*)(void) everywhere. If you need both void * and a function pointer, you must use a struct or union or allocate void * to point to the function pointer, or ensure that your code only runs on platforms where J.5.7 is implemented ;)
void (*)() is recommended by some sources too, but right now it seems to trigger a warning in latest GCCs because it doesn't have a prototype.

With some modification you can avoid pointer conversations:
#include <stdio.h>
#include <string.h>
void foo(void)
{
puts("foo");
}
void bar(void)
{
puts("bar");
}
void quux(void)
{
puts("quux");
}
typedef void (* voidfunc)(void);
voidfunc ptr_list[] = {foo, bar, quux};
char *name_list[] = {"foo", "bar", "quux"};
voidfunc find_ptr(char *name, char *names[], voidfunc ptrs[], int length)
{
int i;
for (i = 0; i < length; i++) {
if (strcmp(name, names[i]) == 0) {
return ptrs[i];
}
}
return NULL;
}
int main() {
voidfunc fptr;
fptr = find_ptr("quux", name_list, ptr_list,
sizeof(ptr_list) / sizeof(ptr_list[0]));
fptr();
return 0;
}

As pointed out in other answers you shouldn't be allowed to assign a function pointer to an object pointer such as a void*. But you can safely assign a function pointer to any function pointer. Use reinterpret_cast in C++.
Let me give an example:
typedef void(*pFun)(void);
double increase(double a){return a+1.0;}
pFun ptrToFunc = reinterpret_cast<void(*)(void)>(increase);
the plain
pFun ptrToFunc = increase;
doesn't compile on several compilers.

I'm answering this old question because it seems that one possible solution is missing from existing answers.
The reason why the compiler forbids the conversion is that sizeof(void(*)(void)) can be different than sizeof(void*). We can make the function more generic, so that it can handle entries of any size:
void *find_item(char *name, char *names[], void *items, int item_size, int item_count)
{
int i;
for (i = 0; i < item_count; i++) {
if (strcmp(name, names[i]) == 0) {
return (char*)items + i * item_size;
}
}
return NULL;
}
int main() {
voidfunc fptr;
fptr = *(voidfunc*)find_item("quux", name_list, ptr_list,
sizeof(ptr_list[0]),
sizeof(ptr_list) / sizeof(ptr_list[0]));
fptr();
return 0;
}
Now the find_entry() function doesn't need to directly handle the item at all. Instead it just returns a pointer to the array, and the caller can cast it to a pointer-to-funcpointer before dereferencing it.
(The code snippet above assumes the definitions from original question. You can see full code also here: try it online!)

Related

how should i interpret this typedef declaration in c? [duplicate]

I am trying to understand what this means, the code I am looking at has
in .h
typedef void (*MCB)();
static MCB m_process;
in .C
MCB Modes::m_process = NULL;
And sometimes when I do
m_process();
I get segmentations fault, it's probably because the memory was freed, how can I debug when it gets freed?
It defines a pointer-to-function type. The functions return void, and the argument list is unspecified because the question is (currently, but possibly erroneously) tagged C; if it were tagged C++, then the function would take no arguments at all. To make it a function that takes no arguments (in C), you'd use:
typedef void (*MCB)(void);
This is one of the areas where there is a significant difference between C, which does not - yet - require all functions to be prototyped before being defined or used, and C++, which does.
It introduces a function pointer type, pointing to a function returning nothing (void), not taking any parameters and naming the new type MCB.
The typedef defines MCB as the type of a pointer to a function that takes no arguments, and returns void.
Note that MCB Modes::m_process = NULL; is C++, not C. Also, in C, the typedef should really be typedef void (*MCB)(void);.
I'm not sure what you mean by "the memory was freed". You have a static pointer to a function; a function cannot be freed. At most, your pointer has been reset somewhere. Just debug with a memory watch on m_process.
Let's take an example
typedef void (*pt2fn)(int);
Here, we are defining a type pt2fn. Variables of this type point to functions, that take an integer as argument and does not return any value.
pt2fn kk;
Here, kk is a variable of type pt2fn, which can point to any function that takes in an integer as input and does not return any value.
Reference:https://cs.nyu.edu/courses/spring12/CSCI-GA.3033-014/Assignment1/function_pointers.html
It's a function pointer. You get a SEGMENTATION FAULT because you are trying to make a call to a function which address is invalid (NULL).
According to your specific sample, the function should return no value (void) and should receive no parameters ().
This should work:
void a()
{
printf("Hello!");
}
int main(int arcg, char** argv)
{
m_process = a;
m_process(); /* indirect call to "a" function, */
// Hello!
}
Function pointers are commonly used for some form of event handling in C. It's not its only use though...

Undefined behavior when passing a pointer to a function with a formal parameter of pointer to const?

I have been working on some code that is similar to the following:
typedef struct
{
unsigned char x;
unsigned short y;
unsigned char[NUM_DEFINED_ELSEWHERE];
} My_Struct;
static My_Struct my_useful_struct; // Variables initialized elsewhere in code.
void myFunction(const My_Struct * p_my_struct)
{
/* Performs various read-only actions utilizing p_my_struct. */
}
void myOtherFunction(void)
{
static My_Struct * p_struct = &my_useful_struct;
myFunction(p_struct);
}
My code compiles without any problems, but when reviewed I was told that unless I typecast p_struct that this could lead to undefined behavior on certain platforms (i.e. 8051). However, I never even received a warning on the compiler. Is it true that not typecasting the pointer when passing it to the function with (const My_Struct *) could lead to undefined behavior?
The reason that I declared the above function with a pointer to const was because I wanted to be able to handle both a pointer to const and a pointer. Is it bad coding practice not to typecast in the above situation?
Thanks for your help!
This is absolutely fine; the compiler performs an implicit conversion from My_Struct * to const My_Struct *. §6.3.2.3 of the C99 spec says:
For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type; the values stored in the original and converted pointers shall compare equal.
Furthermore, even if you declare the function with two inconsistent declarations, such that one file sees it declared like this:
void myFunction(My_Struct * p_my_struct);
even though it's actually defined like this:
void myFunction(const My_Struct * p_my_struct) { ... }
even that is allowed by the spec, even though the compiler doesn't know to perform an implicit conversion, because My_Struct * and const My_Struct * have the same representation (so the conversion is a no-op, anyway).
(Thanks to Christoph and awoodland for their comments clarifying the latter situation. In a previous version of this answer, I wrongly claimed that that would be undefined behavior.)
Edited to add: The reverse — defining a function with a declaration with a pointer-to-non-const parameter, but calling it using a declaration with a pointer-to-const parameter — is also allowed, for the same reason; but attempting to actually modify the data could well result in undefined behavior, depending on where it's from. (A char * can by initialized a string constant, for example, but it's undefined behavior to try to modify the data in that constant.)
Type casting constness onto or off of things is something I consider bad practice - there is generally nothing wrong with passing a non-const pointer into a function expecting a const one.
The exception is if there is some reason that the data can change part way through the execution (e.g. another thread touching the data pointed at) - then you might have a problem, but its not the sort of problem that typecasting will prevent. In this case you need to make your logic thread safe.
Don't forget that the const keyword can't be used by the compiler to guarantee constness either, although it can be used to detect problems where you think data should not change, but the compiler expects that you want to change it... its more of a documentation tool for you than anything else.
First I assume the & in the myFunction(&p_struct) call is a typo and what you really meant is myFunction(p_struct).
static My_Struct * p_struct = &my_useful_struct;
myFunction(p_struct);
When you pass p_struct there is absolutely no reason to cast the p_struct pointer in the function call. This is perfectly valid to pass a pointer to T in a function where the parameter is pointer to const T.
In the C Standard this is ruled by the constraints of the assignment operator (C99, 6.5.16.1p1). In a function call of a function declared with a prototype, the arguments are converted as if by assignment to the type of the corresponding parameters (C99, 6.5.2.2p7).
This works for me and I don't think the const pointer parameter yields undefined behavior, the compiler does an implicit conversion before calling the function:
typedef struct
{
unsigned char x;
unsigned short y;
unsigned char[NUM_DEFINED_ELSEWHERE];
} My_Struct;
static My_Struct my_useful_struct; // Variables initialized elsewhere in code.
void myFunction(const My_Struct * p_my_struct)
{
/* Performs various read-only actions utilizing p_my_struct. */
}
void myOtherFunction(void)
{
static My_Struct * p_struct = &my_useful_struct;
myFunction(p_struct);
}

Pointer to function assignment, C

I don't understand why the following code generates a warning:
int func(double a, int b, char c)
{
return 0;
}
int main()
{
int(*myPointer)() = func;
return 0;
}
I thought that in C, a function with an empty parameters list mean a function that can receive an unknown number of parameters. func4 happens to receive 3 parameters. So why is it incompatible with myPointer?
Its especially confusing because the following does compile without warning:
void boo()
{
return;
}
int main()
{
int(*pointerDude)(double) = boo;
return 0;
}
What's going on?
The difference between the two cases is explained like this: if you pass a parameter to a function that accepts none, you are just consuming some memory on the stack. If you don't pass any parameter to a function that accepts a few, the latter is going to read random data from the stack.
Update: changed to community wiki to add these corrections from Pascal Cuoq:
Casts of function pointer in both directions are legal, informative warnings from the compiler notwithstanding. Calling a function with the wrong prototype is illegal in both cases. Some ABIs mandate that the function clean up the stack, in which case passing parameters to functions that accept none corrupt the stack as surely as not passing parameters to functions that expect them.
C99 6.3.2.3 par. 8:
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
This is the warning you get:
warning: initialization from incompatible pointer type
You are passing void which means that will require a cast. You should use the right types.
IIRC C compiler has certain assumptions which can cause very odd bugs because you're not telling it how much stack space it needs whenever that function is called. Especially since the definitions don't match this might allow someone to inadvertently read your function pointer declaration and assume no parameters and have the function return garbage. If you really want to take variable numbers of parameters use my_func(...) and varargs.
A warning is just that, a warning. Honest.
In that case, the compiler knows you have an incorrect function pointer type and it blatantly tells you that. If you try to pass a number of parameters different then 3, then it will be issued an error.
I think that the problem is related to the casting of the parameters, because char is not 32 bits. Note that if you change the char to int this works fine. It is related to automatic promotion of variables.
Compare the two:
int func();
int func(double a, int b, int c)
{
return 0;
}
and
int func();
int func(double a, int b, char c)
{
return 0;
}
gcc gives you warning for the second, but not for the first
In C an empty parameter list means that the function does not take any parameters. I believe you are confusing an empty parameter list with varargs.
Changing your first example to include the parameters will remove the warning.
int func(double a, int b, char c)
{
return 0;
}
int main()
{
int(*myPointer)(double, int, char) = func;
return 0;
}

Can't compile with void variable in C

test.c
int main () {
void a;
return 0;
}
I use gcc to compile but it gives me an error:
error: variable or field 'a' declared void
From what I read here,
I thought I can declare void variable without problem.
As your link states:
A variable that is itself declared void (such as my_variable above) is useless; it cannot be assigned a value, cannot be cast to another type, in fact, cannot be used in any way.
This means that although syntactically correct, a void declaration is not useful to anything, this is why GCC could consider it an error. Even if it would compile, you won't be able to do anything with the variable, so I guess your question is just related to testing this behavior.
In fact void is useful just when we're talking about pointers (void*) since it allows you to declare a generic pointer without specifying the type.
No, but you can declare a void pointer: void *. A void * can hold any object pointer.
void *'s are only guaranteed to hold object (i.e. data) pointers
[but]
it is not portable to convert a function pointer to type void *
Although the book states that void a; is a valid statement, I don't believe it has ever been standards compliant. That being said, the first edition of the book was from 1987, so it could also be carry-over from older implementations of GCC.
void *x; is a valid statement.
void x; is not a valid statement.
A function that returns a pointer to void is also valid.
Why is this so?
When a variable is declared in a function, the compiler has to allocate a memory space for a variable. But when a variable is of type void, the compiler doesn't know how many bytes to allocate for this variable. So this will not work for the compiler.
However, the pointer to void is different. A pointer can be of type void which can be read as an int or a double or a float or a short or a char at the time of reading. In this case, explicit typecasting required or automatic type promotion is done by the compiler.
e.g.
int
function_A( void *x )
{
int *p = (int *)x;
return *p;
}
double
function_B( void *x )
{
double *p = (double *)x;
return *p;
}
An important note: C does not allow direct typecast of dereference of void pointer.
What I mean by this is that you cannot do this:
double
function_B( void *x )
{
return (double)*x;
}
Conceptually, this makes perfect sense. But C doesn't allow this.

Call a void* as a function without declaring a function pointer

I've searched but couldn't find any results (my terminology may be off) so forgive me if this has been asked before.
I was wondering if there is an easy way to call a void* as a function in C without first declaring a function pointer and then assigning the function pointer the address;
ie. assuming the function to be called is type void(void)
void *ptr;
ptr = <some address>;
((void*())ptr)(); /* call ptr as function here */
with the above code, I get error C2066: cast to function type is illegal in VC2008
If this is possible, how would the syntax differ for functions with return types and multiple parameters?
Your cast should be:
((void (*)(void)) ptr)();
In general, this can be made simpler by creating a typedef for the function pointer type:
typedef void (*func_type)(void);
((func_type) ptr)();
I should, however, point out that casting an ordinary pointer (pointer to object) to or from a function pointer is not strictly legal in standard C (although it is a common extension).
I get awfully confused when casting to function types. It's easier and more readable to typedef the function pointer type:
void *ptr = ...;
typedef void (*void_f)(void);
((void_f)ptr)();
In C++: reinterpret_cast< void(*)() > (ptr) ()
The use of reinterpret_cast saves you a set of confusing parentheses, and the < > clearly sets the type apart from the call itself.

Resources