7 ms·
struct Meow* p_cat = (struct Meow*)malloc(sizeof(struct Meow)); struct Bark* p_dog = p_cat; > Most compilers warn, but this is standards-conforming ISO C cod
by hvdijk 6y ago
struct Meow* p_cat = (struct Meow*)malloc(sizeof(struct Meow));
struct Bark* p_dog = p_cat;
> Most compilers warn, but this is standards-conforming ISO C code that is required to not be rejected
Bollocks. That is a constraint violation, ISO C requires a diagnostic for it, and ISO C allows that diagnostic to be an error. The constraint is in the section "Simple assignment", which contains "One of the following shall hold:" followed by a list detailing when assignments are valid. Pointers to different structure types on the LHS vs the RHS are nowhere in that list.
- DiabloD3 6y agoI'd also like to chime in that both clang and gcc will complain that I didn't explicitly cast it.
- quietbritishjim 6y agoThe question here is whether it is a warning or an error. "Complain" could mean either. Which did you mean?
- DiabloD3 6y agoAssuming that you have called gcc as `gcc -Wall`, it will warn, but not error. What the author of the article wants, I believe, is the equivalent of some combination of `-Wall -Werror` and `-pedantic -pedantic-errors` by default, and that's certainly unreasonable. gcc, however, isn't C, just a popular compiler for it, and clang might error on this particular one, but my memory is fuzzy. Someone else might want to chime in here.
- fanf2 6y agoYou don’t need any warning flags for these diagnostics because they are constraint violations, so a bare `cc` invocation will complain about them.
- hvdijk 6y agoA bare cc (or gcc or clang) invocation is not meant to be standard-conforming and will both reject standard-conforming code and leave out standard-mandated diagnostics. To accept all standard-conforming code, you need the -std=c[...] option e.g. to prevent it from picking up non-standard keywords. Without -std=c[...], GCC would flag a syntax error for the perfectly valid void asm(void) {}, because it detects asm as a keyword contrary to what the standard requires. Without -pedantic, no diagnostic will be issued for e.g. void f(int i) { int x[i]; } with cc -std=c90, even though C90 requires a diagnostic for an array where the length is not a constant. For GCC, this is documented at <https://gcc.gnu.org/onlinedocs/gcc-10.2.0/gcc/Standards.html#C-Language> https://gcc.gnu.org/onlinedocs/gcc-10.2.0/gcc/Standards.html....
- DougBTX 6y ago> Bollocks. Only because it is misquoted, the sentence ends: > this is standards-conforming ISO C code that is required to not be rejected unless you crank up the -Werror -Wall -Wpedantic etc. etc. etc.
- kachnuv_ocasek 6y agoIt's not misquoted. The author claims that the code "is required to not be rejected", which OP demonstrated to be false.
- deleted 6y ago[deleted]
- DougBTX 6y agoSeems you're right, all I can see is that a diagnostic should be produced, not that the code should be accepted. The impression I get is that when they say diagnostic, they really mean: "this is an error, but carry on if you like." That informs the perspective that adding warnings is a breaking change, as there is no formal distinction between error and warning diagnostics. Perhaps there's an informal "standard" between compilers for which should be which somewhere else?
- hvdijk 6y agoFor GCC and clang, while -Werror turns all diagnostics into errors, even those for valid code, -pedantic-errors will only turn the standard-mandated diagnostics into errors. This is the only reliable way I know of to determine whether the compiler considers the code to violate ISO C's rules. (I say "the compiler considers" because there are corner cases where GCC and clang disagree in their interpretation of the standard.) If your warning does not get upgraded to an error with -pedantic-errors, the warning is about something the compiler authors consider relevant to warn about but the standard allows.
- gwd 6y agoWhat's even stupider is that I'd be willing to bet it's also UB. If it is, it means an ISO-C-compliant compiler is allowed to generate code that does absolutely anything; which makes the worries over adding a warning kind of ridiculous.
- wtallis 6y agoI wonder if this might be a case where the assignment isn't undefined behavior, but an attempt to dereference the pointer and access the wrong struct type's members would be.
- fanf2 6y agoThe Bark Meow pointer conversion isn’t UB itself, provided you convert the pointer back to the correct type before dereferencing it.
- kstenerud 6y agoA diagnostic is not a rejection. The full quote explains his thought: "Yes, two entirely unrelated pointer types can be set to one another in standards conforming C. Most compilers warn, but this is standards-conforming ISO C code that is required to not be rejected unless you crank up the -Werror -Wall -Wpedantic etc. etc. etc." Unless you make warnings errors (-Werror), it probably will warn, but will not reject the code (fail to compile).
- hvdijk 6y agoIt specifically makes the false claim that ISO C requires it to not be rejected, right there in what you quoted. ISO C requires no such thing. ISO C requires compilers to diagnose it and allows them to choose whether to accept or to reject it. If compilers want to make it a hard error, they're perfectly free to do so. The fact that they don't is their choice, not something ISO C imposes on them.
- deleted 6y ago[deleted]
- raxxorrax 6y agoThis is dangerous of course because dogs are larger than cats, but I think he is correct. While every compiler I tried has this warning enabled for assignments or comparisons by default, I don't think the standard explicitly forbids it. Could be wrong though.
- hvdijk 6y ago> I don't think the standard explicitly forbids it. I already wrote exactly where the standard explicitly forbids it in the message you replied to.
- raxxorrax 6y agoI looked it up... > both operands are pointers to qualified or unqualified versions of compatible types Not sure, but I still would say he was correct. The compiler might not be able to check if the types are compatible, so the warning as a standard behavior is anticipatory. Sensible, yes.
- hvdijk 6y ago"Compatible type" is defined in the standard as well. It doesn't mean "whatever the compiler thinks is compatible", it's what the section "Compatible type and composite type" defines as compatible. Different struct types are not compatible.
- BunsanSpace 6y agoThe standard does not. It's common to get a data payload of struct A, but cast it's pointer to struct B which is a subset of struct A (at is the first elements. Actually in the Win32 API this is done a lot. Often you're even given a void* to some arbitrary data that you need to figure out what should be there. Sometimes it's not even a pointer it's two integers packed together, in the case of WM_MOUSEMOVE messages.
- richardwhiuk 6y agoA* -> void* -> A* is legal A* -> void* -> B* is undefined A* -> B* is undefined If you want to get the first element, you want, &(A->first), not a cast. The cast isn't guaranteed to be defined, and isn't guaranteed to be the same.
- zvrba 6y agoI can't bother to dig out the reference, I know that but C explicitly allows such assignment when `p_dog` is the first member of `p_cat`, i.e., when struct Meow { struct Bark dog; }
- hvdijk 6y agoNope, C doesn't allow such assignment even then. You're thinking of casts. For casts, the C standard requires that a pointer to a struct can convert to a pointer to its initial member and vice versa, this is specified under "Structure and union specifiers". You need to actually spell it out with a cast though, C doesn't allow that to be done as an implicit conversion.
- NovemberWhiskey 6y agoIt's been a while since I called myself a C expert, but that's not an assignment - it's an initialization. Those are not the same things in C; I think if you go look at your C standard for the constraints on initialization, they are different from and weaker than those for assignment.
- kllrnohj 6y agoCorrect, the warning is about initialization: "warning: initialization of 'struct Bark ' from incompatible pointer type 'struct Meow '" https://godbolt.org/z/zK45Ys https://godbolt.org/z/zK45Ys
- hvdijk 6y agoYou're correct that initialization is not assignment, but the assignment section is still the relevant place to look: the initialization section says "the same type constraints and conversions as for simple assignment apply". But that isn't obvious and I should have spelled that out.
- NovemberWhiskey 6y agoBut that's in the semantics section; not the constraints section; right?
- hvdijk 6y agoHeh, true. It's pretty clearly meant to mean that the constraints for simple assignment apply as constraints for initialization too, but if you were to argue that the constraints of simple assignment are imported as semantics for initialization, and therefore violations render the behaviour undefined (not requiring any diagnostic), I wouldn't be able to point to anything that shows that to be wrong other than common sense, and common sense can be wrong. The same applies to the return statement, which says "is converted as if by assignment" outside of its "Constraints" section as well.