Never mix unsigned and signed operands. Prefer signed. If you need to convert an operand, see (2).
https://nullprogram.com/blog/2024/05/24/You cannot even check the signedness of a signed size to detect an overflow, because signed overflow is undefined!
The remaining argument from what I can tell is that comparisons between signed and unsigned sizes are bug-prone. There is however, a dedicated warning to resolve this instantly.
It makes sense that you should be able to assign a pointer to a size. If the size is signed, this cannot be done due to its smaller capacity.
Given this, I can't understand the justification. I'm currently using unsigned sizes. If you have anything contradicting, please comment :^)
int somearray[10];
new_ptr = somearray + signed_value;
or
element = somearray[signedvalue];
this seems almost criminal to how my brain does logic/C code.
The only thing i could think of is this:
somearray+=11; somearray[-1] // index set to somearray[10] ??
if i'd see my CPU execute that i'd want it to please stop. I'd want my compiler to shout at me like a little child, and be mean until i do better.
-Wall -Wextra -Wextra -Wpedantic <-- that should flag i think any of these weird practices.
As you stated tho, i'd be keen to learn why i am wrong!
Why?
By the definition of ptrdiff_t, ISTM the size of any object allocated by malloc cannot be out of bounds of ptrdiff_t, so I'm not sure how can you have a useful size_t that uses the sign bit?
[1] https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3531.txt
Add a namespacing macro and you have a whole generics system, unlike that in TFA.
So, it might add more value to have the C std add an `#include "file.c" name1=val1 name2=val2` preprocessor syntax where name1, name2 would be on a "stack" and be popped after processing the file. This would let you do types/functions/whatever "generic modules" with manual instantiation which kind of fits with C (manual management of memory, bounds checking, etc.) but preprocessor-assisted "macro scoping" for nested generics. Perhaps an idea to play with in your slimcc fork?
"struct Goose { float weight; }" and "struct Beaver { float weight; }" would remain incompatible, as would "struct { float weight; }" and "struct { float weight; }" (since they're declared without tags.)
unwind•4h ago
jolmg•20m ago
Making a parameter optional when it isn't a pointer? I don't touch C often, but curiously enough I was just met with this case while making a change in i3:
I added that `fullscreen_layer` param, which is an enum, and later found that I needed to make it optional. Maybe there's a better convention for cases like this, but I couldn't think of anything better than adding that `any_layer` boolean to decide whether to use or ignore `fullscreen_layer`. If `fullscreen_layer` were a pointer, it can just be set to `NULL`, but it's not. If the definition allowed without much duplication, I'd split the function into 2, one with the fullscreen_layer param and another without. Again, not an option. I don't want to pollute the enum for the concern of a single function either. If this were Haskell, the convention here would be to wrap the `fullscreen_layer_t` in a Maybe (a parameterized type).Extending on the example of this post to write a maybe parameterized type in C, it works:
I'm not going to use this, because it's kind of unconventional in C and it's just a single case in what I'm working on. However, if this problem were a more common occurrence, something like this might be nice to use to avoid having multiple parameters to pass around when one could be enough.