Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is pointer conversion through a void pointer well defined?

Suppose I have some structures defined like:

struct foo { int a; };
struct bar { struct foo r; int b; };
struct baz { struct bar z; int c; };

Does the C standard guarantee that the following code is strictly conforming?

struct baz x;
struct foo *p = (void *)&x;
assert(p == &x.z.r);

The motivation for this construct is to provide a consistent programming idiom for casting to a pointer type that is known to be compatible.


Now, this is what C says about how structures and its initial members are convertible:

Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.
C.11 §6.7.2.1¶15

This is what it says about void pointer conversions:

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.
C.11 §6.3.2.3¶1

And this is what it says about converting between object 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 aligned68) for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer.

68) In general, the concept ‘‘correctly aligned’’ is transitive: if a pointer to type A is correctly aligned for a pointer to type B, which in turn is correctly aligned for a pointer to type C, then a pointer to type A is correctly aligned for a pointer to type C.
C.11 §6.3.2.3¶7

My understanding from the above is that converting an object pointer to an object pointer of a different type via a void * conversion is perfectly fine. But, I got a comment that suggests otherwise.

like image 990
jxh Avatar asked Jul 15 '15 01:07

jxh


People also ask

Can you cast any pointer to a void pointer?

Any pointer to an object, optionally type-qualified, can be converted to void* , keeping the same const or volatile qualifications.

What does casting to void pointer do?

A void pointer is a pointer that can point to any type of object, but does not know what type of object it points to. A void pointer must be explicitly cast into another type of pointer to perform indirection. A null pointer is a pointer that does not point to an address. A void pointer can be a null pointer.

What is the advantage of void pointer in C?

Why do we use a void pointer in C programs? We use the void pointers to overcome the issue of assigning separate values to different data types in a program. The pointer to void can be used in generic functions in C because it is capable of pointing to any data type.

Can you do pointer arithmetic on void pointer?

Since void is an incomplete type, it is not an object type. Therefore it is not a valid operand to an addition operation. Therefore you cannot perform pointer arithmetic on a void pointer.


1 Answers

Your example is strictly conforming.

The 2nd sentence from §6.7.2.1 ¶15 (A pointer to a structure object, suitably converted, points to its initial member ... and vice versa.) guarantees the following equalities :

(sruct bar *) &x == &(x.z)
(struct foo *) &(x.z) == &(x.z.r)

As you are at the beginning of the struct, no padding can occur, and my understanding of the standard is that the address of a struct and of its first element are the same.

So struct foo *p = (void *) &x; is correct as would be struct foo *p = (struct foo *) &x;

In that particular case, the alignment is guaranteed to be correct per §6.7.2.1 ¶15. And it is always allowed to pass via a void *, but it is not necessary, because §6.3.2.3 ¶7 allows the conversion between pointers to different objects, provided there is no alignment problem

And it should be noted that §6.2.3.2 ¶7 also says : 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 that means that all those pointers point in fact to the lowest addressed byte of x.r.z.a. So you could also pass via pointers to char because we also have :

(char *) &x == (char *) &(x.z) == (char *) &(x.z.r) == (char *) &(x.z.r.a)
like image 170
Serge Ballesta Avatar answered Nov 16 '22 00:11

Serge Ballesta