How does casting a function actually work in C? - c

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.

Related

C: How to access a function pointer stored in a void pointer (void *)?

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.

Why it is recommended to cast a pointer to a generic one before printing?

OK, I have heard things like you should cast a pointer to a generic one i.e void * before printing it and must practice the use of %p placeholder instead of %d in the printf function for printing them.
I just have a feeling that it might be done to prevent truncation of large addresses while printing or Is it something else? But the point is that if you are on a machine with 64 bit pointers and 32 bit integers; use of %p instead of %d will solely do the job.
Is anyone is aware of any practical situations where this casting technique is helpful?
Because the specification of the %p specifier is that it prints a void *. It doesn't know how to print any other type of pointer.
With printf the caller must convert the argument to the right type ; the printf function cannot perform any conversions because it does not have access to the type information about what arguments you actually passed in. It can only assume that you passed the right ones.
C99 7.19.6.1#7
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.
C99 7.19.6.1#9
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
"Undefined behaviour" means anything can happen. In practice, you probably get away with it if the pointer you pass has the same size and representation as void * does. But you should not rely on undefined behaviour.
On modern systems, all object pointers (i.e. not function pointers) have the same size and representation. If you know you are on such a system, and it is not really important if the program misbehaves, then you probably get away with passing the wrong pointer type.
One place where it would be important is if you try to print a function pointer; as there are modern systems which have function pointers a different size to object pointers. It's not guaranteed that casting a function pointer to void * will be allowed by the compiler, but at least you'll get a compiler error message when you try it.

Why do we cast return value of malloc? [duplicate]

This question already has answers here:
Do I cast the result of malloc?
(29 answers)
Closed 9 years ago.
Could someone explain to me why do some programmers use (char*) in front of the malloc? I know that it returns void but why do I want it to return just char memory? I'm sorry, I'm just a newbie in programming. Thank you
No need to cast return value of malloc as its return type is void*.
Can someone explain why do some programmers use (char *) in front of the malloc?
They are doing wrong (most probably) by casting it (in good programmers opinion).
As wiki says:
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 C1. The lack of a specific pointer type returned from malloc is type-unsafe behavior 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.
One may "cast" this pointer to a specific type:
int *ptr;
ptr = malloc(10 * sizeof (*ptr)); /* without a cast */
ptr = (int *)malloc(10 * sizeof (*ptr)); /* with a cast */
ptr = reinterpret_cast<int *>(malloc(10 * sizeof (*ptr))); /* with a cast, for C++ */
There are advantages and disadvantages to performing such a cast.
Advantages to casting:
Including the cast allows a program or function to compile as C++.
The cast allows for pre-1989 versions of malloc that originally returned a char *.
Casting can help the developer identify inconsistencies in type sizing should the destination pointer type change, particularly if the pointer is declared far from the malloc() call.
Disadvantages to casting:
Under the ANSI C standard, the cast is redundant.
Adding the cast may mask failure to include the header stdlib.h, in which the prototype for malloc is found. In the absence of a prototype for malloc, the standard requires that the C compiler assume malloc returns an int. If there is no cast, a warning is issued when this integer is assigned to the pointer; however, with the cast, this warning is not produced, hiding a bug. On certain architectures and data models (such as LP64 on 64-bit systems, where long and pointers are 64-bit and int is 32-bit), this error can actually result in undefined behavior, as the implicitly declared malloc returns a 32-bit value whereas the actually defined function returns a 64-bit value. Depending on calling conventions and memory layout, this may result in stack smashing. This issue is less likely to go unnoticed in modern compilers, as they uniformly produce warnings that an undeclared function has been used, so a warning will still appear. For example, GCC's default behavior is to show a warning that reads "incompatible implicit declaration of built-in function" regardless of whether the cast is present or not.
If the type of the pointer is changed, one must fix all code lines where malloc was called and cast (unless it was cast to a typedef).
1. Emphases are mine.
As the return type of malloc is void*, when you assign the result to a pointer, it is converted implicitly to the new type. So, there is no need for explicit casting. Actually, using an explicit cast is discouraged, as described here.
malloc returns void*, which is a generic pointer that can point to any type of data. The (char*) is an explicit type conversion, converting the pointer returned by malloc from a pointer to anything, to a pointer to char. This is unnecessary in C, since it is done implicitly, and it is actually recommended not to do this, since it can hide some errors.
If you need the code to compile as C++ too, and not just as C, you will however need the explicit conversion, since C++ doesn't perform the implicit conversion.
malloc() return a void*, as malloc() does not know how its caller will be using the memory it allocated on the heap.
So it's up to you, the caller to cast the (void*), into the appropriate type of pointer, that you want to use inside the memory.
(int*) to store integers.
(char*) to store characters etc..
Having said so, you don't have to explicitly cast the return of a malloc() call. And in some cases, doing so may result in bugs.
Kindly read up the issue here
What's wrong with casting malloc's return value?
Specifically, what's dangerous about casting the result of malloc?

qsort and bsearch function..."pointer"

I wonder, when we create the function
int compar(const void *, const void *)
and we merely pass its name into one of the parameters of qsort and bsearch, how do those functions recognize said essentially random word (since we've never explicitly stated it is a function pointer, but rather an actual function) and use it as a parameter? Is there an explicit cast in the function declarations of qsort and bsearch or something?
This has nothing to do with the qsort and bsearch functions themselves, rather function names are implicitly converted by the compiler into function pointers as per the standard, C11 6.3.2.1 Language / Conversions / Other operands / Lvalues, arrays, and function designators:
A function designator is an expression that has function type. Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, a function designator with type "function returning type" is converted to an expression that has type "pointer to function returning type".
That means that, when you pass compar to qsort() (for example), it's the actual pointer to the function that gets passed, not some "essentially random word".
The reasons for implicitly treating a function identifier as its address lie long ago in the past but (and this whole section is supposition on my part, based on what I'd like to consider intelligent reasoning, but in no way definitive) it's likely to be because the value of a function makes no sense. With an identifier int i = 5;, it has a value (5), and you can also use &i to get it's address.
However, for functions, they don't really have values as such. You can call them to generate a value, xyzzy(), and you can get their address, &xyzzy, for later calling via a function pointer.
But they have no real intrinsic value separate from their address like the integer i does. So early compilers (pre-ANSI) simply allowed the shorthand xyzzy to mean &xyzzy. And, of course, since the original mandate of ANSI was to codify existing practice rather than create a new language, they preserved this behaviour.
If K&R had gone the other way and decided xyzzy should be a call to the function passing no parameters, the same as xyzzy(), the world would be a different place :-)

function pointer to dynamic library in two different ways

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.

Resources