5 ms·
> memset (sprtemp,-1, sizeof(sprtemp)); Yikes. I think this article undersells the point somewhat. This line of code undermines the type system by spraying -1'
by munchler 8mo ago
> memset (sprtemp,-1, sizeof(sprtemp));
Yikes. I think this article undersells the point somewhat. This line of code undermines the type system by spraying -1's into an array of structs, so the only surprise to me is that it took this long to break.
- direwolf20 8mo agoC has no particularly strong type system, and it works on typical platforms with all types up to the introduction of _Bool. And maybe float/double, but I think it gives a NaN.
- Sharlin 8mo ago`spriteframe_t` is defined as typedef struct { // If false use 0 for any position. // Note: as eight entries are available, // we might as well insert the same name eight times. boolean rotate; // Lump to use for view angles 0-7. short lump[8]; // Flip bit (1 = flip) to use for view angles 0-7. byte flip[8]; } spriteframe_t; which is okay to splat with all-ones as long as `boolean` is either a typedef for a fundamental type(*) or an enum – because C enums are just ints in a trenchcoat and have no forbidden bit patterns! The C99 `bool`/`_Bool` is, AFAICS, the first type in C that has fewer values than possible bit patterns. So yeah, on C99 and C++ this always had UB and could've broken at any time – though I presume compiler devs were not particularly eager to make it ill-behaved just because. But in pre-C99 it's entirely fine, and `rotate == true || rotate == false` could easily be false without UB. --- (*) other than `char` for which setting the MSB is… not UB but also not the best idea in general.
- zozbot234 8mo agoC99 does not use bool unless you explicitly include stdbool.h, which won't be in any pre-C99 code. By default, you just get _Bool.
- direwolf20 8mo agoMaybe changing the type of the variable to int was the better solution?
- pwagland 8mo agoAnd, indeed, if you look at the author's writeup, you see exactly that the generated code satisifes `(rotate == true || rotate == false) == false`, since rotate is checked explicitly against 0 and 1. The essence of the difference is: > When boolean is an enum, the compiler does exactly what I expected – the == false condition checks if the value is equal to 0, and the == true condition checks if the value is equal to 1. > However, when boolean is actually _Bool, the == false check is transformed into != 1, and the == true check is transformed into != 0 – which makes perfect sense in the realm of boolean logic. But it also means that for a value of 255, hilarity ensures: since 255 is neither 0 nor 1, both conditions pass! So a value of 255 also makes both checks fail for the enum, but because of the ordering of the code, it was expected to evaluate as != false. Had the check: ``` if (sprtemp[frame].rotate == false) ``` been written as: ``` if (sprtemp[frame].rotate != true) ``` then it would work for the `bool` type, but not the `enum` type, at least in C23 mode. Assumedly the C++ mode (effectively) treated the boolean as an enum, or possibly as `false == 0`, `true != 0`.