3 ms·
The ISA might force someone to extend a value to 32 bits (debatable, but let’s go with it). It never forces you to treat an unsigned int as signed. It also does
by codeflo 4y ago
The ISA might force someone to extend a value to 32 bits (debatable, but let’s go with it). It never forces you to treat an unsigned int as signed. It also doesn’t require inserting UB into the process.
- simias 4y agoI agree, the whole signed vs. unsigned generally feels like an afterthought in C (probably because, to a certain extent, it was). `char`'s sign being implementation-defined is a pretty wild design choice that wasted many hours of my life while porting code between ARM and x86. UBs are not required, but you need them if you want C to behave as a macro-assembler as well as allowing for aggressive optimizations. For instance `a << b` if b is greater than a's width is genuinely UB if you write portable code, different CPUs will do different things in this situation. Defining the behaviour means that the compiler would have to insert additional opcodes to make the behaviour identical on all platforms. You may argue that it's still better than having UB but that's just not C's design philosophy, for better or worse.
- codeflo 4y agoThat’s true, I’d add something more. Your reasoning about hardware differences would only justify implementation-defined behavior, not undefined behavior. The distinction is important here: undefined behavior is when the compiler can make surprising optimizations in other parts of the code assuming something doesn’t happen.
- jcranmer 4y agoI imagine the reason oversized shifts are UB is because some 40-year-old computer hardware trapped on oversized shifts, as traps are always UB in C.
- gsliepen 4y agoIt's worse than that. `char`'s signedness being implementation defined is one thing, but then having the standard library provide a function called `getchar()` that returns not a `char` but an `unsigned char` cast to an `int` is diabolical.
- tsimionescu 4y ago> For instance `a << b` if b is greater than a's width is genuinely UB if you write portable code, different CPUs will do different things in this situation. Defining the behaviour means that the compiler would have to insert additional opcodes to make the behaviour identical on all platforms. Your seem to be mixing up implementation defined behavior and undefined behavior. It would have been perfectly reasonable to make this choice if signed integer ovwrflow were implementation-defined, but it is unfortunately not - it is undefined behavior instead. This means that a program containing this instruction is not valid C and may "legally" have any effect whatsoever.