3 ms·
As long as fread internally writes into it as char* it’s fine. char* is the special case that aliases everything else. The ”Just dumb bytes” kind of pointer if
by sharpneli 6y ago
As long as fread internally writes into it as char* it’s fine. char* is the special case that aliases everything else. The ”Just dumb bytes” kind of pointer if you will.
- abainbridge 6y agoYou are correct. However, C programmers expect to be able to cast a void* to something other than a char* and use it. It is kind of necessary because the language doesn't support generics. I feel that the reasons for calling this UB are not as good as the reasons for making it valid code.
- sharpneli 6y agoThe reasons for that are performance. So that one doesn't have to assume everything aliases everything else. It could be more clear though, like having explicit alias qualifier which would make it alias all and by default nothing aliases, or vice versa. Right now there is no easy way to make two unrelated types alias, one has to go via char* or use unions. You can cast void* to something else and it will work, but you can't expect to get a random void* and presume it has some valid well defined data for you to read. You must know where it came from and what's been done to it. As a rule of thumb if you just write dumb bytes it's char*. If it's anything else you must know what you're doing and there are ways to perform type punning that's within the spec.
- abainbridge 6y ago> The reasons for that are performance. So that one doesn't have to assume everything aliases everything else. Can you expand on that? I don't understand. Edit: I see the answer in one of your other comments: > If len and array are both of the same type then the compiler must assume they can alias (or one of them is char*). One has to explicitly state with restrict that they cannot alias. I'd happily take that hit. I can put restrict in the hot paths of my code. I'm tempted to say I want restrict to be the default, but I haven't thought that through.
- armitron 6y agoYou can use memcpy or unions. No C programmer that knows the language should be casting and dereferencing void* to anything other than char* for portable code.
- abainbridge 6y ago> You can use memcpy or unions. I know. I think the reason that this an area that causes lots of debate is because the majority of C programmers from 20 years ago would not have thought the memcpy or unions approach was a better idea than casting and dereferencing void* . The casting approach used to "just work" unless you violated the alignment requirements on your platform, and that was a problem 20 year-ago C programmers were happy to take on. For next time this discussion comes up, I'll try to think of a good example of when the void* approach yields easier to maintain code :-) BTW, you can also use -fno-strict-aliasing to make the C compiler sort-of work like it did 20 years ago. I believe this is what the Linux Kernel does but I couldn't be certain that it is for exactly this reason.
- armitron 6y agoWell, it's not the act of casting/dereferencing void* that's UB (otherwise malloc would trigger UB) but the potential for violating alignment requirements. If you're certain there is no violation (such as with malloc), then go ahead and do it. -fno-strict-aliasing is unrelated to this issue. It removes the strict aliasing assumption from the compiler (another source of potential issues if not understood), but void* (and char*) are explicitly allowed to alias to anything regardless.
- abainbridge 6y agoI don't understand. Compiler experts have told me that the Godbolt example I posted at the start of the thread (https://godbolt.org/z/ugSDmr https://godbolt.org/z/ugSDmr) is incorrect C code because casting void* to uint64_t* is UB. I modified the code to ensure that the data is 8-byte aligned (I think I've done this correctly). It still goes "wrong". https://godbolt.org/z/Pnxnb8 https://godbolt.org/z/Pnxnb8 In either case, adding -fno-strict-aliasing fixes it.