It is common to assign pointers with allocations using an implicit function-return void * conversion, just like malloc()'s:
void *malloc(size_t size);
int *pi = malloc(sizeof *pi);
I would like to perform the same assignment while passing the address of the target pointer, and without explicitly casting its type from within the function (not within its body, nor arguments).
The following code seems to achieve just that.
- I would like to know whether the code fully conforms with (any of) the C standards.
- If it doesn't conform, I would like to know if it's possible to achieve my requirement while conforming to (any of) the C standards.
.
#include <stdio.h>
#include <stdlib.h>
int allocate_memory(void *p, size_t s) {
void *pv;
if ( ( pv = malloc(s) ) == NULL ) {
fprintf(stderr, "Error: malloc();");
return -1;
}
printf("pv: %p;\n", pv);
*((void **) p) = pv;
return 0;
}
int main(void) {
int *pi = NULL;
allocate_memory(&pi, sizeof *pi);
printf("pi: %p;\n", (void *) pi);
return 0;
}
Result:
pv: 0x800103a8;
pi: 0x800103a8;
Some platforms are capable of storing pointers that can only identify coarsely-aligned objects (e.g. those of type
int*
) more compactly than pointers that can access arbitrary bytes (e.g. those of typevoid*
orchar*
). The Standard allows implementations targeting such platforms to reserve less space forint*
than forvoid*
. On implementations that do that, would generally be impractical to allow avoid**
to be capable of updating either anint*
or achar*
interchangeably; consequently, the Standard does not require that implementations support such usage.On the other hand, the vast majority of implementations target platforms where
int*
andchar*
have the same size and representation, and where it would cost essentially nothing to regard avoid*
as being capable of manipulating both types interchangeably. According to the published Rationale document, the Spirit of C indicates that implementations should not "prevent programmers from doing what needs to be done". Consequently, if an implementation claims to be suitable for purposes like low-level programming that may involve processing pointers to different kinds of objects interchangeably, it should support such constructs whether or not the Standard would require it to do so; those that don't support such constructs on platforms where they would cost essentially nothing should be recognized as unsuitable for any purposes that would benefit from them.Compilers like gcc and clang would require using
-fno-strict-aliasing
to make them support such constructs; getting good performance would then likely require usingrestrict
in many cases when appropriate. On the other hand, since code which exploits the semantics available via-nno-strict-aliasing
and properly usesrestrict
may achieve better performance than would be possible with strictly conforming code, and support for such code should be viewed as one of the "popular extension" alluded to on line 27 of page 11 of the published Rationale.I don't think it's possible to do it in a 100% standard-compliant manner, because non-void pointers are not guaranteed to have the strictly same size as a
void*
.It's the same reason the standard demands explicitly casting
printf("%p")
arguments tovoid*
.Added: On the other hand, some implementations mandate that this work, such as Windows (which happily casts
IUnknown**
tovoid**
).I think your code might provide some interesting problems due to casting void* to void** and dereferencing it. According to GCC this is not a problem but sometimes GCC lies. You can try
Note that in your original code you had to cast
int**
tovoid*
(implicit) and then explicitly cast tovoid**
which could really confuse your compiler. There might still be an aliasing problem due to the fact that main'sint *pi
is accessed as and assigned avoid
pointer. However, a quick scan of the C11 standard is inconclusive in that regard (see http://open-std.org/JTC1/SC22/WG14/).Types
int**
andvoid**
are not compatible You are casting p, whose real type is int**, to void** and then dereferencing it here:which will break aliasing rules.
You can either pass a void pointer and then cast it correctly:
or return a void pointer.
There is an option to use a union:
As far as I understand it, this example conforms to standard.
Use static asserts to guarantee that the sizes and alignment are the same.
No, this is not compliant. You're passing an
int**
asvoid*
(ok), but then you cast thevoid*
to avoid**
which is not guaranteed to have the same size and layout. You can only dereference avoid*
(except one gotten frommalloc
/calloc
) after you cast it back to the pointer type that it originally was, and this rule does not apply recursively (so avoid**
does not convert automatically, like avoid*
).I also don't see a way to meet all your requirements. If you must pass a pointer by pointer, then you need to actually pass the address of a
void*
and do all the necessary casting in the caller, in this casemain
. That would be... defeating your scheme.