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.)
Related
In K&R2 book, on page 119 in the section on function pointers, there is the following parameter declaration for a function pointer:
(int (*)(void*,void*))(numeric ? numcmp : strcmp)
numcmp and strcmp are function names, and numeric is a boolean variable that decides which of these two functions is pointed to by the function pointer that the expression declares.
I don't understand how and why this works. If I were attempting to write this expression, my attempt would be more like:
int (*(numeric ? numcmp : strcmp))(void*,void*)
The best way I can make sense of the K&R construction is that the first parenthesized part - (int (*)(void*,void*)) - acts as a function, and the second - (numeric ? numcmp : strcmp) - acts as the function parameter, and the whole returns the function pointer declaration. But to think of it this way doesn't connect with anything I've learned about C.
I have read some excellent guides on how to understand complex pointer expressions in C. You basically "spiral out" from the innermost expression outward. But this one has me stumped, it doesn't conform. Could someone please explain?
(int (*)(void*,void*)) is a normal type-cast.
If we create a type-alias
typedef (int (*function_type)(void*,void*));
it would perhaps be easier to understand when used:
(function_type) (numeric ? numcmp : strcmp)
In short, the ternary expression returns a pointer to a function, and then the result (the function-pointer) is cast to a specific type.
The expression is from p119 of Brian W Kernighan and Dennis M Ritchie
The C Programming Language, 2nd Edn (1988).
It is simply a cast of one of two function pointers (selected by the ternary expression) to a common type, int (*)(void *, void *) to match the signature of the variant of the qsort() function that is written on p120 of K&R2.
However, IMO, that piece of code officially runs foul of 'undefined behaviour' according to the C standard.
C11 [§6.3 Conversions]
§6.3.2.3 Pointers ¶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.
You can check the requirements on compatible types in §6.2.7 Compatible type and composite type and §6.7.6.3 Function declarators (including prototypes) ¶15.
The code referred to in the question is an invocation of a variant of the standard C qsort() function. The standard function has the signature:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
In the code in the book, they are using their own, related function qsort() with the rather different signature:
void qsort(void *lineptr[], int left, int right, int (*comp)(void *, void *));
Now, the code in the qsort() variant is going to invoke the function identified by comp with two void * values. So, to avoid undefined behaviour, the function that is passed to qsort() as the comparator should have the signature:
int comparator(void *p1, void *p2);
Now, the code passes the comparator using:
(int (*)(void *, void *))(numeric ? numcmp : strcmp)
The strcmp function implementations on p106 do not quite match the standard C int strcmp(const char *, const char *); it is their own minor variant of it missing the const qualifiers (int strcmp(char *, char *)). However, the code on p119 includes <string.h> so it probably is the standard version that is used. The signature of thenumcmp` function is given as:
int numcmp(char *, char *);
The cast in the call is legitimate — you can convert a function pointer from one type to another (and back again). What is not legitimate — in the strictest interpretation — is that their variant of qsort() is going to invoke those functions as if their type was int function(void *, void *) and the standard says "that's undefined behaviour".
Additionally, §6.5.15 Conditional operator says that the two expressions on either side of the : must satisfy one of a series of 6 conditions, the relevant one of which is:
both operands are pointers to qualified or unqualified versions of compatible types;
Now, given that both the functions have the signature int function(char *, char *), this is OK. If the strcmp() was the standard C version, it is treading on thin ice because of the const-qualifiers.
Given that it is a custom qsort() and that the two comparators have the same signature, it would be reasonable to use this signature:
void qsort(void *lineptr[], int left, int right, int (*comp)(char *, char *));
Then it would not be necessary to coerce the types when qsort() is called — the function pointer argument would be simply:
(numeric ? numcmp : strcmp)
and the code in the qsort() wouldn't need to change because there's an automatic conversion in C from void * to any other type — char * in this case.
Summary
In practice, you will almost invariably get away with the code shown in K&R2. But strictly, the code is invoking undefined behaviour because it is not casting the function pointers back to their original type(s).
If you are using the standard C qsort(), you should always pass a comparator that matches the signature:
int comparator(const void *p1, const void *p2);
You should not, therefore, need a cast on the function pointer in the call to qsort() because that signature will be used by qsort() to call your function. Inside your comparator function, the code will convert the two const void * values into suitable (const) pointers of the correct type, and run the comparisons using those types.
I've seen some examples of array of function-pointers (here, for example)
In the examples I've seen the array holds functions that have a return value of the same type (all int's, or all void's for example).
But I'm wondering can you have an array that holds function-pointers of different types?
The next code won't compile:
#include <stdio.h>
void Empty_Funcion()
{
;
}
int funcAdd(int a, int b){
return a+b;
}
int main()
{
int ret = 0;
void *array[5] = {&Empty_Funcion, &funcAdd, &Empty_Funcion, &funcAdd, &Empty_Funcion};
ret = (*array[1])(5,7);
printf("%d\n", ret);
return 0;
}
It says the problem is with the assignment ret =... "void value not ignored as it ought to be".
You can do it like this:
ret = ( ( int (*)(int,int) ) array[1] )(5,7);
You need to cast to pointer to function type with the correct signature.
But I'm wondering can you have an array that holds function-pointers of different types?
As noted in Anatoly's answer, your code doesn't work because your array intends to declare contain pointers-to-functions that return void, but then you try invoking it as a pointer-to-function that returns int. These are incompatible types, so an explicit cast is required. And, as noted in section 6.3.2.3/8 of the ISO C99 standard, casting a function pointer to a different function pointer type and back again is permitted:
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.
That said, I don't see any point to doing this. The function pointer cast is a static cast (a cast known to the compiler) and not a dynamic cast, so you must manually keep track of which elements in your array are of type void (*)() and which are of type int (*)(int, int). It'd instead be simpler to have a separate array for each function pointer type and avoid casting altogether. Doing so would be less error-prone since you would not risk invoking a function pointer as the wrong type (which would be undefined behavior).
Update:
You've changed your question so that array is now an array of void* pointers. Note that although normal pointers may be freely cast to and from void*, this is not true for function pointers (although it is considered to be a common extension in many implementations).
Your array is not declared as an array of function pointers, it is declared as an array of pointers to void.
To declare the array as an array of function pointers you can do:
int (*)(int,int) array[5] = ...
or for clarity:
typedef int (*my_function_pointer_type)(int,int);
my_function_pointer_type array[5] = ...
In theory, you cannot call a function which returns void and expect it to return something. This is against the C standard. In practice, if you do this you most likely get an unpredictable value, but in some cases (such as trying to return a structure) with some ABIs you can get a crash.
The best way is to match the type of your "dummy" function to the type of other functions being put into the array.
I have heard that pointers should first be cast to void to ensure consistency of values across different platforms and should use %p format specifier. Why is it and what exactly are the problems?
int x=100;
int *pi=&x;
printf("value of pi is: %p",(void*)pi);
printf is a variadic function and must be passed arguments of the right types. The standard says %p takes void *.
Implicit cast doesn't take place for variadic functions.
Quoting from N1570 7.21.6.1 The fprintf function
p : The argument shall be a pointer to void. The value of the pointer is
converted to a sequence of printing characters, in an implementation-defined
manner.
Internal presentation or size of different pointer types is not necessarily same.
For example on one system sizeof(void*) may be 2, but sizeof(int*) is 1.
Since printf is variable argument function, it cannot check the types of incoming parameters. If you passed int* to it, it would read wrong number of bytes, because it expects void*.
p conversion specification in printf requires an argument of type void *. C says if you pass an argument of an other type the call invokes undefined behavior.
Besides that, pointer objects of different types are not required to have the same representation: C does not guarantee that sizeof (void *) == sizeof (int *) for example. C only guarantees that void * has the same representation as pointers to character types.
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.
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.