The following two are the same but C99 standard leaves casting from void * to a function pointer undefined.
Can somebody explains how the second one works? Its a little bit confusing!
int (*fptr)(int);
fptr = (int (*)(int))dlsym(handle, "my_function");
int (*fptr)(int);
*(void **) (&fptr) = dlsym(handle, "my_function");
On the first line (of the second code paste) declares a function pointer (I imagine that you know that).
Now, dlsym(3) is a call that returns a void *.
So the second line can also be read as:
*((void **) (&fptr)) = dlsym(handle, "function");
Otherwise said: instead of casting the function result as int (*)(int), and affecting the given result to fptr; it casts a pointer on fptr (or it casts fptr's address: a pointer on a pointer) as a void**. Then it dereferences this pointer, effectively giving fptr (the same as the original one, but without the int (*)(int) type), which then gets the result of the dlsym call. It's just a way to 'trick' the compiler into not triggering warnings/errors about a type mismatch. Please also note that even if the syntax you chose is a matter of taste, it's something you should fully understand before you use it in any program you release.
I hope it helps ;)
The difference is the same as the one between:
float f = 3.14;
int i = (int)f;
and
float f = 3.14;
int i = *(int*)&f;
The first is a regular cast of the value, which in some cases (int <--> float, or back in the 8086 days near pointer <--> far pointer) causes some conversions; and in some cases (some casts between function pointers and regular pointers) doesn't even compile.
The second is a raw bitwise copy, which the compiler will always accept but bypasses any conversion and may lead to writing a variable into another variable of different size. Can be highly dangerous, especially with function pointers.
The reason the second version is legal is in the following part of the ISO Standard:
6.3.2.3 Pointers 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.
(**void), as well as &fptr are pointers to objects (since &fptr is a pointer to a pointer to a function), so the cast in your second expression is explicitly allowed by the statement above. Your first expression is trying to convert a pointer to an object (rather a pointer to void which is a special case in the standard) to a pointer to a function (which is not an object), which is not allowed by the standard as you pointed out.
Related
Confused as to how one can access a function pointer stored in a void pointer (void *).
Let's say you have this:
void *functions[] =
{
&sqrt, // int ft_sqrt(int nb);
&power,
&logN,
&factorial;
};
// An array of void pointers, each storing a function pointer.
If I wanted to access the sqrt function, my guess would be the following:
(int (*)(int)) functions[0](x)
But my guess is wrong:
error: called object type 'void *' is not a function or function pointer
So how would one access one of these functions ?
Strictly speaking, you can't. A conversion between a function pointer and a void pointer is not possible. void* was never a generic pointer type for function pointers, only for object pointers. They are not compatible types.
In practice, any pointer will very likely have the size required by the address bus of the system, so object pointers and function pointers will very likely have the same representation. Not guaranteed by the standard though, and there are some exotic systems where this equivalence doesn't hold true. So you can cast between void* and a function pointer, but what will happen is undefined behavior. You will be relying on system-specific non-standard extensions.
Slightly better would be to use a function pointer type such as void (*)(void) as the generic pointer. You can convert to/from different function pointers, what will happen is compiler-specific (implementation-defined behavior). That is, the code will still be non-portable, but at least you don't risk a program crash from invoking undefined behavior.
It's a matter of operator precedence: The function call operator have higher precedence than the casting operator.
That means your expression (int (*)(int)) functions[0](x) is really equal to (int (*)(int)) (functions[0](x)).
You need to explicitly add parentheses in the correct places to cast the pointer: ((int (*)(int)) functions[0])(x).
A much better solution IMO would be to have an array of pointers to functions, so the array elements already is of the correct type:
typedef int (*function_ptr)(int);
function_ptr functions[] = { ... };
Then no casting is needed: functions[0](x).
Then you also would be safe from the issues mentioned in the answer by Lundin.
The last parameter of this line in main() makes me lost
// declaration
void qsort(char *linep[], int left, int right, int (*compare)(void *, void*);
// use
main(){
qsort((void**) lineptr, 0, nlines-1, (int (*)(void*,void*))(numeric ?
numcmp : strcmp));
}
I understand the ternary operator but let's say numeric == 0 then what does this mean?
(int (*)(void *, void*))strcmp;
Do datatypes of function parameters mismatch?
int strcmp(const char*, const char*);
void qsort( , , , int(*)(void*)(void*);
Can I typecast a function pointer?
In your code, using the cast
(int (*)(void *, void*))strcmp;
means, strcmp() is a function pointer, which takes two void * arguments and returns an int.
Usually, for function pointers, casting is a very bad idea, as quoting from C11, chapter §6.3.2.3
[...] If a converted
pointer is used to call a function whose type is not compatible with the referenced type,
the behavior is undefined.
but, in your case, for the argument types, char * and void * alias each other, so the typecasted type is compatible with the actual effective type(s), so (at a later point) the function call is defined.
Yes, you can cast a function pointer to a pointer to a function with a different signature. Depending on your calling convention (who cleans the stack up? The caller or the callee?) calling that function will be bad if there is a different number of arguments or their sizes differ.
Neither is the case here: On your standard architecture (sun workstations, Linux PCs, raspberry PI) the argument pointers to different data types are represented identically so that no harm is expected. The function will read the 4 or 8 byte value from the stack and interpret the memory pointed to as data of the expected type (which it should have though, e.g. don't use a float compare function on strings; it may throw because arbitrary bit patterns can be NaNs etc.).
I wanted to alert you to the fact that today's standard lib's qsort has a different function signature (and semantic) than K&R's example. Today's qsort gets a pointer to the beginning of an element vector and calls the compare function with pointers to the elements in the array; in the case of an array of string pointers, the arguments are pointers to pointers which are not suitable for strcmp(). The arguments have to be dereferenced first. The linux man page for qsort has an example for a strcmp wrapper which does just that. (The man page web export appears somewhat garbled, but is still readable.)
Knowing more C++ than C I wondered if someone could explain the reason why malloc() always returns a pointer of type void, rather than malloc having been implemented with some mechanism which allows it to return a pointer of the type the user passed in? It just seems a little "hacky" constantly explicitly casting the returned void pointer to the type you want.
Well, in C you don't have to do the cast, so your point is moot. That is, these two statements are 100% equivalent:
char *x = malloc(100);
char *y = (char *)malloc(100);
Conversions to and from void * are implicit in C. So, to address your question, the very reason malloc returns void * is so that you don't have to cast.
Besides that, in C there's no way to pass type information around, so doing something like:
char *x = malloc(100, char);
is not possible.
If you're in C++, the cast is necessary, but you shouldn't be using malloc anyway - that's what new is for, and it does handle the type information correctly.
It's not hacky at all, from C standard ISO/IEC 9899 2011, section 6.2.2.3:
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.
So a pointer to void* is a valid pointer to whatever type you want without the need of explicit casting.
In addition to this you can't dynamically pass a type to a function to let so that it will return the correct type, you can pass just the size itself (so malloc would be able to allocate size_t count * size_t size but not return the correctly type in any case).
C has no mechanism for "passing a type" at all. Also, in C, conversion from void* to a pointer of any other type is automatic (no cast is needed) so malloc works naturally in C. It's only in C++ where malloc requires casts to work.
There are two reasons, first, malloc doesn't know why you need memory. So it just return number of bytes asked to return. Secondly you cannot de-reference void * easily so it can help you to avoid accidents.
int *p;
p = (int *)malloc(sizeof(int)*10);
I have some confusions about what I read from the following site about memcpy()(and malloc()):
http://www.cplusplus.com/reference/cstring/memcpy/
In that page,the following 2 lines are clearly stated:
destination
Pointer to the destination array where the content is to be copied, type-casted to a pointer of type void*.
source
Pointer to the source of data to be copied, type-casted to a pointer of type const void*.
But immediately after that,in the code,there is no casting to void* in the following two lines where memcpy() is used:
memcpy ( person.name, myname, strlen(myname)+1 );
memcpy ( &person_copy, &person, sizeof(person) );
Please answer the following 2 questions arising from this premise:
1) In C's case(as opposed to C++) is it all right and advisable not to cast to void* the return type or the arguments in memcpy() just as it is all right and advisable not to cast to void* the return type of malloc() in C?If so,as I intuitively feel, why is it explicitly stated in that reputed site that we need to cast it to void* (even though it doesn't use that in the code).Is that site wrong about it?
2) Now the real contradiction about that reputed site.Consider the following
http://www.cplusplus.com/reference/cstdlib/malloc/
In the case of malloc() ,in the description, it is written as if it is optional to cast to void* the return type (exact words "..can be cast to the desired type.."),unlike in the case of memcpy() above where it is said that it is to be cast into void*.But while in memcpy() the casting is not done even though it is written that it is to be cast,in the case of malloc(),the casting to void* is done even though it's written it can be cast to void*.Now I see something wrong in this as for C we are not supposed to cast malloc()'s return to void*.
To put the discrepancies in a nutshell again lest the people answering get confused in my wordy description:
--Is it advisable in C not to cast to void* the return and arguments of memcpy()?
--Is that site wrong about malloc() as it casts malloc() return to void* in C code.
From ISO/IEC 9899:2011 of C language specification, section 6.3.2.3, page 55:
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.
So you basically never need to cast the result of a void* to the desired type, neither you need to do the opposite.
->for first question
memcpy, the cast is not required in C. It would be in C++.
->for second question
malloc returns a void pointer (void *), which indicates that it is a pointer to a region of unknown data type. The use of casting is required in C++ due to the strong type system, whereas this is not the case in C. The lack of a specific pointer type returned from malloc is type-unsafe behaviour according to some programmers: malloc allocates based on byte count but not on type. This is different from the C++ new operator that returns a pointer whose type relies on the operand
In C we directly assign void* to any type and vice-versa, we don't have to explicitly typecast.
int *i_ptr = (int *)0xABCD; //some address
printf("address :%p\n",i_ptr);
void *v_ptr = i_ptr; //no need to explictly typecast
printf("address :%p\n",v_ptr);
float *f_ptr = v_ptr; //this will throw error in cpp
printf("address :%p\n",f_ptr);
output:
address :0xabcd
address :0xabcd
address :0xabcd
All these are valid statements in C, but in CPP float *f_ptr = v_ptr will cause error invalid conversion from ‘void*’ to ‘float*’.
int foo(char *c) {...}
main() {
int (*thud)(void *);
thud = (int (*)(void *))(foo);
}
What actually happens during the evaluation of the assignment?
There is a difference between the cast type and foo; the cast type is a pointer and foo is a function. So, does the compiler convert what's in '(foo)' into a pointer to foo and only then make the cast? Because nothing else seems to make sense; the other option is that the function itself is converted to a pointer to a function that gets a void* and returns an int, and as far as I know a function is a label to a piece of code in memory and thus cannot become a pointer, which is a variable.
The name of a function is a pointer when used as such. It's somewhat similar to how the name of an array is a pointer to its first element.
That being said, calling a function through a pointer with a different type than the function's actual prototype (as your example does) is undefined behavior. Don't do it.
Addendum
If a converted pointer is used to call a function whose type is not compatible with the pointed-to type, the behavior is undefined.
from section 6.3.2.3 of the C standard.
In C, absolutely nothing. It is just compiler glue to prevent you from doing something stupid. In C, the caller is responsible for maintaining the stack frame, so the cast is necessary when you invoke the function (i.e. arguments and the return value are pushed onto the stack). This makes it safe(r) since the caller's stack will not likely be mutated improperly. However, the invoked function can still mess up the caller's stack in certain rare cases.
I should clarify that the assignment copies the function pointer. But in C, all function pointers are just pointers. The type and casting is all compiler glue.
Another clarification: The standard specifies (in 6.5.2.2) that the behavior is undefined if the caller uses incompatible types. For example, casting a function which returns void into one which returns an int and then calling that function, the "returned" value is meaningless. It's a good idea to cast the function into a compatible type before calling it, or you may see unexpected results.
A pointer in C is an address, i.e. a number stored in some place. A function in C is an address to some code. Those two are one of the same.
The correct term is decay. Function foo decays to a pointer to foo before the cast. The cast itself will be a no-op on all platforms I can think of.
Note, however, that the behavior of a program containing such a cast is undefined by the C standard.
This was going to be a comment to Rick C. Petty's answer - but it doesn't fit in 300 characters.
The C standard is not very restrictive - pointers to objects (and functions aren't objects) can be converted to 'pointer to void' and back without problem. POSIX requires that pointers to functions are all the same size and can be converted to pointer to void.
POSIX 2008 - General Information - The Compilation Environment
2.12.3 Pointer Types
All function pointer types shall have the same representation as the type pointer to void. Conversion of a function pointer to void * shall not alter the representation. A void * value resulting from such a conversion can be converted back to the original function pointer type, using an explicit cast, without loss of information.
Note:
The ISO C standard does not require this, but it is required for POSIX conformance.