can a void pointer safely point to annother pointer? - c

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.

Related

Type of address and pointers in c

I have 2 questions about pointers in c.
1) from my understanding the & returns the memory address of a variable. For example:
int x=10;
int *p=&x;
So I think that the & will return the memory address of x and that memory address is type int* because the variable type of x is int.
Also because the type of the address is int* I believe that is the reason that only an int* (and void *) pointer can point in the address (they are the same type).
Any thoughts about that? comments? I don't know if I am correct.
2) It's about the void pointer. I know that the void* pointer can point to any type of variable. For example
int x=10;
void *ptr=&x;
Now I have a function:
void * foo(some parameters)
{
// just for this example let's say that I return the address of a local variable
// I know that is wrong to do so because when the foo ends
// the local variables deallocate
int k=10;
void *ptr=&k;
return ptr;
}
So my pointer is type void but it points to int* memory address. So ptr will save the address of k and when I return ptr the address of k is returned which is type int* . But my function is type void*.
What is happening here?
According to the C 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.
So for example in this code snippet
int x = 10;
void *p = &x;
the expression &x in the right side of the assignment has the type int *. According to the quote it may be converted to pointer of the type void * in the left side of the assignment.
1) Yes all of that is correct.
2) The type of the pointed-at data remains int no matter what kind of pointer that points at it. (This is known as effective type in formal C.) In your example you return a void pointer so that's the type the caller gets. The information of what type it pointed at is lost, from the point you do void *ptr=&k; and onward. This is why void pointers are problematic to use.
1) You are correct
2) It is simply returning a void * that is pointing to k - a local variable. (Any pointers can be cast to void pointers).
You are correct in saying that you should not use the returned value as k no longer exists

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.

Are all pointers guaranteed to round-trip through void * correctly?

Is it guaranteed, in C, that any pointer type can round-trip through void * successfully?
That is, something like the following guaranteed to work:
typedef struct {
...
} A;
A *p = ...;
void *v = p;
A *p2 = v;
// use p2 here
No matter what the type of A?
Object pointers can indeed be round-tripped through void*. From C11 6.3.2.3 paragraph 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.
Note that the opposite direction is not true, when you convert a void pointer to some object pointer and back you are not guaranteed the same value as what you started with.
Note also that this is not true of function pointers; however, all function pointer types are mutually round-trippable: Paragraph 8 says:
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.
Moreover, object pointers are also round-trippable among themselves (not involving void pointers), subject to some constraints, by paragraph 7:
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) for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer.

What exactly does void * mean

I have seen void * explained as a pointer to an unused chunk of memory. I have also seen void * described as a pointer to any type, or a pointer to any type can be cast to void *.
From what I know, int * means a pointer to type int. So keeping this in mind, what does void * mean literally? Is it a pointer to type void? This doesn't seem right because I did not know that void could be a type.
void * is a pointer to void.
C11: 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.
The compiler will not let you dereference a void* pointer because it does not know the size of the object pointed to but you need to cast void * type pointer to the right type before you dereference it.
Let's begin with this example:
int a = 65;
int *q = &a;
void *p = q;
char *c = p;
(source: qiniudn.com)
we define an int variable a, and an int pointer q pointing to it. p in the void * pointer.
The beginning address of a is 0x8400(just for simplicity).
A pointer is an address, no more.
No matter what type of pointer, they have the same memory size, and their value is an address.
So,
printf("%p, %p", *p, *q);
will display:
0x8400, 0x8400
Type: how you interpret the date
As you see in the graph, the data in memory is 65000000(this is little endian). If we want to use it, we have to specify what it is! And type does that.
printf("%d %c", *p, *q);
If we print it as integer, we get 65. If we print them as char, we get A(asciicode).
And p + 1 pointer to 0x8401, q + 1 points to 0x8404.
void *: a universal type
According to wikipedia:
A program can probably convert a pointer to any type of data (except a function pointer) to a pointer to void and back to the original type without losing information, which makes these pointers useful for polymorphic functions.
Yes, void * define a trivial unit of pointer, it can be converted to any pointer and vise versa. But you can't dereference it, because it doesn't specify a type.
If you want to manipulator on bytes, you should always use void *.
Isn't char * the same as void *
Not exactly.
The C language standard does not explicitly guarantee that the different pointer types have the same size.
You can't always hope char * have the same size on different platforms.
And converting char * to int * can be confusing, and mistakes can be made.
It means: a pointer to some memory, but this pointer does not contain any information about the type of data that may be stored in that memory.
This is why it's not possible to dereference a void *: the operation of dereferencing (and obtaining an rvalue, or writing through an lvalue) requires that the bits in the memory location be interpreted as a particular type, but we don't know which type to interpret the memory as.
The onus is on the programmer to make sure that data read in matches the type of data read out. The programmer might help himself in this by converting the void * to a pointer to an object type.
It's useful if you want to have a common interface for dealing with memory of multiple possible types, without requiring the user to do a lot of casting. for example free() takes a void * because the type information isn't necessary when doing the free operation.
void * is a pointer to data of unspecified type. As such, it can't be used directly; it must be cast to a usable datatype before it can be dereferenced.

Is Cast to void** needed?

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.

Resources