I'm writing some library code that exposes a const pointer to users but during certain operations I need to change where this pointer points (behind the scenes switcheroo tricks). One idea I had to solve this problem without encountering UB or strict-aliasing violations was to use a union with a const member:
// the pointed-to objects (in production code, these are actually malloc'd blocks of mem)
int x = 0, y = 7;
typedef union { int * const cp; int * p; } onion;
onion o = { .cp = &x };
printf("%d\n", *o.cp); // <---------------------- prints: 0
o.p = &y;
printf("%d\n", *o.cp); // <---------------------- prints: 7
But I don't know if this is well-defined or not... anybody know if it is (or isn't) and why?
EDIT: I think I muddied the waters by mentioning I was building a library as lots of people have asked for clarifying details about that rather than answering the much simpler question I intended.
Below, I've simplified the code by changing the type from int*
to just int
and now my question is simply: is the following well-defined?
typedef union { int const cp; int p; } onion;
onion o = { .cp = 0 };
printf("%d\n", o.cp); // <---------------------- prints: 0
o.p = 7;
printf("%d\n", o.cp); // <---------------------- prints: 7
int * const cp
to meancp
isconst
or did you wantconst int * cp
meaningcp
points toconst
data? – Madocint * const cp
(the typo was:const int * cp
) – Vannyconst
tells the compiler that it the value will not change later. – Shellbark(int * const *)&myunion
– Vannystruct
orunion
is normally the same address as a pointer to the first element (of any variant in case of aunion
), but it is still not clear how you want to use this. Show an example how the interface and the internal part of the library would look like and how the interface should be used. Explain what you want to achieve. Please edit your question to add all clarification or requested information. This looks like an XY problem. meta.stackexchange.com/questions/66377/what-is-the-xy-problem – Shellbarkstatic int *internal_pointer;
in your library andint * get_pointer(void) { return internal_pointer; }
as the interface to get a copy of the pointer. This way the user cannot modify the pointer value in the library, but the library code can. – Shellbark(int * const *)&myunion
, you can pass them the address of thecp
member which requires no type-cast -&myunion.cp
. – Faubertconst int *cp
that points tox
, which was not definedconst
, it is defined behavior to convertcp
toint *
and use it to accessx
. This is because, in order to setcp
to point tox
, there first had to be anint *
(withoutconst
) pointing tox
(such as&x
). So thatint *
has been converted toconst int *
, and that is the value that ended up incp
. Then C 2018 6.3.2.3 7 says that when a pointer is converted back to its original type, it equals the original pointer. Thus(int *) cp
gives us the original&x
. – Supernatant