@constCast mainly used for those C language interfaces that are poorly written.
Here is a use case of a C interface that might require using @constCast to interact with. As a release interface, it requires that the pointer to the value to be released is a constant pointer.
@constCast is mainly used to handle such legacy C interfaces where the input parameter is actually mutable. In general situations, using @constCast is mostly incorrect.
Yes, I know it is a bad use of @constCast in my demo code. Iâm just wondering that what is the instruction is generated for p2.* = 2; on Linux. Why doesnât this instruction cause crashing?
In addition, from the compilation results, it can be seen that before calling the print function, there is no modification to the rdi register, which means that this print function does not take any input parameters; that is, the printed 1 1 1 has already been hard-coded into the print function at compile time. This is the reason why the printed result is the old value.
As for the reason it didnât crash, we can check from the compiled output which section n was linked into.
npc1054657282@localhost:~/projects/zig-tests$ nm test | grep "test\.n"
000000000119acc0 d test.n
It is linked into the .data section instead of .rodata. This is the reason there was no crash. A crash in Windows may mean that Windows is stricter during linking.
Here is a use case of a C interface that might require using @constCast to interact with. As a release interface, it requires that the pointer to the value to be released is a constant pointer.
Mutable â Const is always safe implicit cast so I donât think this is a correct example. Correct example would be a C api that only accepts mutable char* even though it doesnât mutate it, or struct that contains char* instead of const char* even though its a constant data.
Exactly, this example is more common and more general.
Even in C, this is definitely bad code, but since the C standard never assumes that an object pointed to by a const pointer is immutable, this cannot constitute undefined behavior and ultimately becomes legally bad code. I give this example out of my frustration with many anomalies in the C interface of rocksdb.
How is that? Itâs been while since Iâve written C. But I do think even in C char* coerces to const char* so I donât see the problem here. It would be a problem if the function still modifies the pointer (aka breaks the contract). Freeing the pointer is fine though.
This is an callback interface (function pointer) implemented by the user, which is called when itâs necessary to release resources previously allocated by the user. When I saw this interface with a parameter as a const pointer, I couldnât believe what its purpose actually was, but after reading the context, I had to accept that the timing of its call is intended for the user to release value, even though this interface requires passing a const pointer.
Editor: Iâm not even sure if this counts as bad code in C; maybe some patterns just use such an interface to remind users that the data has never changed since it was allocated, even though it is about to be freed. At least it canât be considered UB, we just have to use @constCast to make it work.
Freeing a pointer doesnât actually mutate it. It makes accessing the address illegal afterwards. Unfortunately libc also made the historical mistake of making free take void* instead of const void* (C++ fixed this with delete). Which makes it really awkward to do APIs that allocate memory and then return a constant pointer to it.
Oh, for me this is a philosophical shock. I have always maintained the practice that âownership heap pointers must be mutable, and when used as constants, you need to create an extra const observer pointer for them,â and the fact that Zigâs Allocator interface requires a mutable pointer for deallocation has kept me thinking this way.
Perhaps in languages like C++ that can annotate ownership, it makes more sense to use const to indicate whether it is mutable, but for languages that lack ownership annotations, I still find it hard to accept that an ownership pointer can be a const pointer.
Const is typically used when you donât indeed own the memory behind that pointer. But in manual memory managed language you still have to tell the owner that you no longer need that resource. Of course there are also const pointers that you should never release, but the type system in most languages do not have enough information to encode such information, thus leaving such details to documentation.
We should try to be precise with the language. A âconst pointerâ is a very different thing than a âpointer to constâ, but people especially from C land often use the terms interchangeably so confuse the discussion about whatâs mutable and what isnât.
Natural language is indeed a big headache . In my native language, âconst pointerâ means pointer to const, while âpointer constâ refers to pointer as const.
The reason for this is clear: two lines down, the @memset(bytes, undefined) call absolutely needs the type of bytes to be []u8. Calling this a âcode smellâ is the kind of thing that has me roll my eyes and say âwell, if you say soâ, since that memset is a useful part of catching use-after-frees in safe modes, and the @constCast is justified in all cases that arenât programmer errors: if the Allocator actually allocated the memory, then thereâs no problem, since itâs legal to write to.
True. If you pass pointer to the free/destroy that wasnât created by one of the allocatorâs create/alloc functions you are already making a mistake. So in this case itâs not that bad, and canât think of a useful allocator that returned read-only memory.