3 ms·
> The correct way of accessing a variable like that is trough an union. It's funny you should say that, because people have been taking the exact opposite view
by pascal_cuoq 11y ago
> The correct way of accessing a variable like that is trough an union.
It's funny you should say that, because people have been taking the exact opposite viewpoint for years: “union do not allow type-punning because it was only clarified in TC3 of C99 that they do. memcpy has always been the correct way to type-pun.”
The bug reporter is referring to the rules described in 6.5:6 and 6.5:7 of C11 (the same rules are included in C99, but interestingly not in C90, meaning that “gcc -std=c90” should go theoretically easy with the type-based optimizations. It doesn't). Here is a link: http://port70.net/~nsz/c/c11/n1570.html#6.5p6 http://port70.net/~nsz/c/c11/n1570.html#6.5p6
And an excerpt for your convenience:
If a value is copied into an object having no declared type using memcpy or memmove, or […], then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one
How do you interpret the above paragraph?
- maxlybbert 11y agoI've been under the impression that unions don't truly allow type punning, but given that the practice was widespread (e.g., it was used in the code Protocol Buffers generated a few years ago), it was a pretty safe bet compilers would support it as an extension. I was also under the impression that the One True Way to type pun was to cast to char*, which is allowed to alias, and then cast again to the type you actually want.
- asgfoi 11y agoI was also under the impression that the One True Way to type pun was to cast to char, which is allowed to alias, and then cast again to the type you actually want.* That clearly doesn't work, but I can see from a naive perspective why some think that. It feels like a nice hack, but a cast to char* doesn't "remove" the original type. To be clear: char* can alias any type, but only char* can alias char*.
- gpderetta 11y agoCasting through chard doesn't help: how do you get to a specific pointer value doesn't really matter. The C aliasing rules are only about dereferencing pointers. What is allowed, as an explicit exception to the aliasing rules, is reading an object representation by dereferencing a char pointer. This is why memcpy is the approved way to do type punning, but you do have to copy.
- derefr 11y ago> How do you interpret the above paragraph? It says that... int a = 5; char *b = memcpy(malloc(sizeof(a)), &a, sizeof(a)); ...should fail. The memcpy(3) src is &a, a pointer-to-int; the memcpy(3) dest is a pointer-to-void (i.e. an untyped pointer) from malloc(3). Thus, memcpy(3)'s return type should be a pointer-to-int.
- pklausler 11y agoIt's being assigned a pointer-to-void, yes?
- derefr 11y agoIt is, yes, according to the typespec of memcpy(3). But according to the standard, it shouldn't be; it should be returning a [whatever-type-src-was-passed-in-as]. I have doubt that there's any way in C to specify variable return type like that—but the C standard, AFAIK, doesn't require that memcpy(3)—or anything else from libc—be implementable in C. It can be, as Lisp would put it, a "special form." To get an implicit pointer-to-char-typed buffer out of memcpy(3), you should have to attach the malloc(3)-returned buffer to a pointer-to-char-typed variable (or give it an explicit cast) to give it a type, and then pass it in as dest.