Is Cast to void** needed? - c

I have the compiler complaining (warning) about the folowing.
Am I missing something? Because I thought this didn't need a cast
char* CurrentCh = some ptr value;
int size;
size = func(&CurrentCh);
with func defined like this
int func(void** ptr);
Compiler warning:
passing argument 1 of 'func'
from incompatible pointer type
Thx

In C you can pass any pointer type to a function that expects a void*. What it says is "I need a pointer to something, it doesn't matter what it points to". Whereas void** says "I need a pointer to a void*, not a pointer to another pointer type".

In C, void * is the generic pointer type. But void ** is not a generic pointer-to-pointer type! If you want to be able to pass a pointer to a pointer in a generic way, you should use void * anyway:
#include <stdio.h>
void func(void *ptr)
{
char **actual = ptr;
const char *data = *actual;
printf("%s\n", data);
}
int main(void)
{
char *test = "Hello, world";
func(&test);
return 0;
}

The cast is necessary as what you do is a form of type punning: You reinterpret the memory which is pointed to from char * to void *.
For these types, the C standard guarantees that this actually works as char * and void * have the same representation. For other type combinations, this may not be the case.
The relevant parts of the standard are section 6.2.5, §27
A pointer to void shall have the same
representation and alignment
requirements as a pointer to a
character type. Similarly, pointers
to qualified or unqualified versions
of compatible types shall have the
same representation and alignment
requirements. All pointers to
structure types shall have the same
representation and alignment
requirements as each other. All
pointers to union types shall have the
same representation and alignment
requirements as each other. Pointers
to other types need not have the same
representation or alignment
requirements.
and less relevant (but perhaps also interesting) section 6.3.2.3, §7
A pointer to an object or incomplete
type may be converted to a pointer to
a different object or incomplete type.
If the resulting pointer is not
correctly aligned for the pointed-to
type, the behavior is undefined.
Otherwise, when converted back again,
the result shall compare equal to the
original pointer. When a pointer to an
object is converted to a pointer to a
character type, the result points to
the lowest addressed byte of the
object. Successive increments of the
result, up to the size of the object,
yield pointers to the remaining bytes
of the object.
Anything beyond that is implementation-specific.

In C, any pointer can downcast to void*, but not to void**. You will need an explicit cast.

Related

Can you cast a "pointer to a function pointer" to void*

Inspired by comments to my answer here.
Is this sequence of steps legal in C standard (C11)?
Make an array of function pointers
Take a pointer to the first entry and cast that pointer to function pointer to void*
Perform pointer arithmetic on that void*
Cast it back to pointer to function pointer and dereference it.
Or equivalently as code:
void foo(void) { ... }
void bar(void) { ... }
typedef void (*voidfunc)(void);
voidfunc array[] = {foo, bar}; // Step 1
void *ptr1 = array; // Step 2
void *ptr2 = (char*)ptr1 + sizeof(voidfunc); // Step 3
voidfunc bar_ptr = *(voidfunc*)ptr2; // Step 4
I thought that this would be allowed, as the actual function pointers are only accessed through properly typed pointer. But Andrew Henle pointed out that this doesn't seem to be covered by Standard section 6.3.2.3: Pointers.
Your code is correct.
A pointer to a function is an object and you're casting a pointer to an object (a pointer to a function pointer) to void pointer and back again; and then finally dereferencing a pointer to an object.
As for the char pointer arithmetic, this is referred to by footnote 106 of C11:
106) Another way to approach pointer arithmetic is first to convert the pointer(s) to character pointer(s): In this scheme the integer expression added to or subtracted from the converted pointer is first multiplied by the size of the object originally pointed to, and the resulting pointer is converted back to the original type. For pointer subtraction, the result of the difference between the character pointers is similarly divided by the size of the object originally pointed to. When viewed in this way, an implementation need only provide one extra byte (which may overlap another object in the program) just after the end of the object in order to satisfy the ''one past the last element'' requirements.
Yes, the code is fine. There's various pitfalls and conversion rules at play here:
C splits all types in two main categories: objects and functions. A pointer to a function is a scalar type which in turn is an object. (C17 6.2.5)
void* is the generic pointer type for pointers to object type. Any pointer to object type may be converted to/from void*, implicitly. (C17 6.3.2.3 §1).
No such generic pointer type exists for pointers to function type. Thus a function pointer cannot be converted to a void* or vice versa. (C17 6.3.2.3 §1)
However, any function pointer type can be converted to another function pointer type and back, allowing us to use something like for example void(*)(void) as a generic function pointer type. As long as you don't call the function through the wrong function pointer type, it is fine. (C17 6.3.2.3 §8)
Function pointers point to functions, but they are objects in themselves, just like any pointer is. And so you can use a void* to point at the address of a function pointer.
Therefore, using a void* to point at a function pointer is fine. But not using it to point directly at a function. In case of void *ptr1 = array; the array decays into a pointer to the first element, a void (**)(void) (equivalent to voidfunc* in your example). You may point at such a pointer to function-pointer with a void*.
Furthermore, regarding pointer arithmetic:
No pointer arithmetic can be performed on a void*. (C17 6.3.2.2) Such arithmetic is a common non-standard extension that should be avoided. Instead, use a pointer to character type.
A pointer to character type may, as a special case, be used to iterate over any object (C17 6.2.3.3 §7). Apart from concerns regarding alignment, doing so is well-defined and does not violate "strict pointer aliasing", should you de-reference the character pointer (C17 6.5 §7).
Therefore, (char*)ptr1 + sizeof(voidfunc); is also fine. You then convert from void* to voidfunc*, to voidfunc which is the original function pointer type stored in the array.
As been noted in comments, you can improve readability of this code significantly by using a typedef to a function type:
typedef void (voidfunc)(void);
voidfunc* array[] = {&foo, &bar}; // Step 1
void* ptr1 = array; // Step 2
void* ptr2 = (char*)ptr1 + sizeof(voidfunc*); // Step 3
voidfunc* bar_ptr = *(voidfunc**)ptr2; // Step 4
Pointer arithmetic on void* is not in the C language. You re not doing it though, you are doing pointer arithmetic on char* which is perfectly OK. You could have used char* instead of void* to begin with.
Andrew Helne seems to be missing the fact that a pointer to a function is an object, and its type is an object type. It is a plain simple fact, not something veiled in a shroud of mystery as some other commentators seem to imply. So his objection to casting a pointer to a function pointer is unfounded, as pointers to any object type can be cast to void*.
However, the C standard doesn't seem to allow using (T*)((char*)p + sizeof(T)) in lieu of (p+1) (where p is a pointer to an element of an array of type T), or at least I cannot find such permission in the text. Your code might not be legal because of that.

Why use a void pointer for dereferencing variables of datatypes?

Dereferencing a float variable using a void pointer:
#include <stdio.h>
int main() {
float a = 7.5;
void *vp = &a;
printf("%f", *(float*)vp); /* Typecasting a void pointer to float for dereference */
printf("\n");
}
Output: 7.500000
Dereferencing a variable using an integer pointer:
#include <stdio.h>
int main() {
float a = 7.5;
int *ip = &a;
printf("%f", *(float*)ip); /* Typecasting an int pointer to float for dereference */
printf("\n");
}
Output: 7.500000
In both, the outputs are same. What is the reason to go for dereferencing of different datatype variable, when we are able to do by typecasting a normal pointer?
Converting any data pointer to void* pointer and back is guaranteed to give back original pointer.
From C11 standard draft N1570:
6.3.2.3 Pointers
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.
Converting data pointer to other data pointer than void* (int* in your example) may work. It depends on the compiler you are using and the system you are on. Not all systems might use same internal representation for different pointer types.
A pointer to an object type may be converted to a pointer to a different object type. If the
resulting pointer is not correctly aligned 68) for the referenced type, the behavior is
undefined. Otherwise, when converted back again, the result shall compare equal to the
original pointer. When a pointer to an object is converted to a pointer to a character type,
the result points to the lowest addressed byte of the object. Successive increments of the
result, up to the size of the object, yield pointers to the remaining bytes of the object.
This is different from strict aliasing rules.
float a = 7.5;
int *ip=&a;
int i = *ip; // Dereferenced using invalid type
Code above breaks strict aliasing rule as dereferenced type is not the same as the original type. This results in undefined behaviour and is always invalid code.
A void pointer is a generic pointer which can hold the address of any type and can be typecast to any type.
In the first case, the program successfully compiled and ran without any warning or error, because using a void pointer to convert from one pointer type to another and then storing or casting it to the final type is safe without losing data.
But in the second case the GCC compiler generated a warning
prog.c: In function 'main':
prog.c:5:9: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
int *ip=&a;
^
clang compiler:
warning: incompatible pointer types initializing 'int *' with an expression of type 'float *' [-Wincompatible-pointer-types]
int *ip=&a;
^ ~~
The C11 Standard, 6.3.2.3, paragraph 7:
A pointer to an object or incomplete type may be converted to a
pointer to a different object or incomplete type. If the resulting
pointer is not correctly aligned for the referenced type, the behavior
is undefined.
A void pointer is (sort of) untyped. It can point to anything without the compiler complaining. e.g. If you have an int variable, you can safely create a void pointer that points to this and pass it around. e.g.
int x = 10;
void *p = &x
is fine but
int x = 10;
float *p = &x;
will upset the compiler
This is especially useful for functions that operate on multiple pointer types or if you will decide what something is at runtime.
However, void pointers cannot be dereferenced (*) directly because the compiler doesn't know their type. So,
printf("%d\n", *p);
will break if p is void pointer. We have to know the size of what it points to to dereference it and this is done using a manual type cast (like what you've done).
In your specific case, you have a pointer that points to a float which you type cast back into float before printing it. So, you will get the same output. The void * pointer is not really playing a big role here.
An example of where you need a void * is the malloc function, If you look at the prototype, it returns a void *. i.e. a block of raw memory. You need to typecast this as a concrete type before you can do pointer arithmetic and dereferencing.

How to interpret section 6.3.2.3 part 7 of the C11 standard?

In the context of another question there was some discussion on whether it was allowed (i.e. would or would not introduce implementation defined or undefined behavior) to cast int** to void** and subsequently assign a value to the dereferenced void*. This brings me to my question on the interpretation of the C11 standard
6.2.5 (28) A pointer to void shall have the same representation and alignment requirements as a pointer to a character type. ...
6.3.2.3 (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.
6.3.2.3 (7) ... When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. ...
My question is whether this
int* intptr = NULL;
void* dvoidptr = &intptr; /* 6.3.2.3 (1) */
*(void**)dvoidptr = malloc(sizeof *intptr); /* using 6.3.2.3 (1) */
conforms with the standard or not? It seems strange to me, but I cannot find a conclusive line of argument why not. void* to void** is guaranteed by 6.3.2.3 and 6.2.5 together with 6.3.2.3 help with the alignment.
Code is not valid.
See the emphasis:
6.3.2.3 (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.
You are converting int** to void* (fine), and then to different type void** (not ok). C gives no quarantee that you can safely convert void* to anything other than the original type (aside from converting to char *)
In addition, *(void**)dvoidptr results in void* when in reality there is int*. What if, for example, sizeof(void*) == 2 and sizeof(int*) == 1? You can convert void* pointer to other type, but you cannot reinterpret it directly as other type.

Can you ever assume typecasting pointers is safe?

I've heard from many people that you cannot guarantee typecasting will be performed lossless. Is that only true if you don't know your processor, that is, you haven't verified the number of bytes used for your data types? Let me give an example:
If you execute the following:
typedef struct
{
int i;
char c;
float f;
double d;
} structure;
size_t voidPtrSz = sizeof(void *);
size_t charPtrSz = sizeof(char *);
size_t intPtrSz = sizeof(char *);
size_t floatPtrSz = sizeof(float *);
size_t doublePtrSz = sizeof(double *);
size_t structPtrSz = sizeof(structure *);
size_t funcPtrSz = sizeof(int (*)(float, char));
printf("%lu\n", voidPtrSz);
printf("%lu\n", charPtrSz);
printf("%lu\n", intPtrSz);
printf("%lu\n", floatPtrSz);
printf("%lu\n", doublePtrSz);
printf("%lu\n", structPtrSz);
printf("%lu\n", funcPtrSz);
…and the output is the following…
4
4
4
4
4
4
4
Can you assume that in all cases you can typecast a specific data type pointer to another data type pointer safely? For example, if you execute this:
int foo(float, char)
{
}
void *bar(void)
{
return (void *)foo;
}
int (*pFunc)(float, char) = bar();
Can you assume with certitude that pFunc has the address of foo?
Regarding your specific code example, let's refer to section 6.3.2.3 of the C99 language standard:
A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
Note that a pointer-to-function is not the same as pointer-to-object. The only mention of pointer-to-function conversions is:
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.
So your code example invokes undefined behaviour.
If we avoid function-pointer conversions, the following paragraph explains everything:
A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. If the resulting pointer is not correctly aligned for the pointed-to type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer.
Note: Converting between pointer types is a separate issue from converting and then dereferencing (in general, that's only valid if you're converting to char * and then dereferencing.)
Can you assume that in all cases you can typecast a specific data type pointer to another data type pointer safely?
Any data pointer can be safely cast to char* or void*. Any char* or void* thus created can be cast back to its original type. Any other data pointer cast leads to undefined behavior when indirection is performed on the pointer.
Any function pointer type can be cast to any other function pointer type, although you should not call a function through the wrong type. Casting a function pointer to void* or any other data pointer type results in undefined behavior.
Is that only true if you don't know your processor, that is, you haven't verified the number of bytes used for your data types?
Even then, you're not safe. When the C standard says a construct has undefined behavior, compiler writers are free to handle the construct as they wish. The result is that even though you think you know a construct with UB will be handled because you know the target CPU, optimizing compilers may cut corners and generate very different code than you expect.
#Oli Charlesworth gives you a great answer.
I hope I can shed a little light on what pointer are so you can better understand pointer mechanics:
A pointer is an address. This address is the address of the first byte of your data. The type of the pointer specifies how many bytes starting from that first byte are part of the data and how those bytes encode the data.
For instance, on gcc x86, if you have a int * p, the value held by p tells the starting address of data, and the type of p (int *) tells that at that address he will interpret 4 bytes (in little endian byte-order) in two's complement signed number representation.
A void * pointer is a "generic pointer". The pointer still holds an address, but the pointer type doesn't specify what kind of data you find there, or even how many bytes form the data, so you can never access data through a void * pointer, but as answered before, you can safely convert between a pointer to void and a pointer to any incomplete or object type.
A pointer to function holds the address of a function, and the type of the pointer tells how to call that function (what parameters and of what kind) and what the function returns.

can a void pointer safely point to annother pointer?

This might be obvious but, can a void pointer safely point to another pointer? i.e. point to a type int *
int i = 5;
int *ip = &i;
void *vp = &ip;
int *nip = *(int **)vp;
int ni = *nip; // == 5?
EDIT: Sorry maybe I'm not being clear, I would like to know if a void pointer can POINT TO a section of memory that has the type of another pointer; without being a void **. just void *
Yes, you can convert any object pointer to void * and back to the original pointer type without loss of information.
From the horse's mouth:
(C99, 6.3.2.3p1) "A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer."
Yes, it can point to any object type1. You can't actually dereference a void pointer since the compiler doesn't know the "real" type behind it. But the pointing aspect is fine.
From C11 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.
1/ "Object type" does not include functions, the rules for converting function pointers are slightly more restrictive.

Resources