Live data from Hacker News

My personal C coding style as of late 2023

nullprogram.com

401–410 of 466 posts

Re: My personal C coding style as of late 2023

#401

Earlier quoted context omitted.

The reality is that C `int` is 32 bits in size. Sure, that's not true for 16 bit targets. But are you really going to port a 5Mb program to 16 bits? It's not worth worrying about. Your code is highly unlikely to be portable to 16 bits anyway. The problem is with `long`, which is 32 bits on some machines and 64 bits on others. This is just madness. Fortunately, `long long` is always 64 bits, so it makes sense to just…

so... what I'm seeing is that C got it wrong relative to the way things actually work and get used. the fact that you had to have tribal knowledge about all of this is why C shouldn't stay for the long term and we should phase out languages into ones with stronger more correct defaults. would a new programmer use "long long"? would they notice immediately that things didn't work if they didn't use it? Rust got it cor…

Rust's integer types are poorly abstracted. The use of specifically sized types for quantities that are not related to hardware is comically ridiculous.

In the C world, only the goofballs do things like use char or int8_t for the number of children in a family, or wheels on a car.

yet that is what Rust code looks like. Almost every Rust code sample I've ever seen sets off my bozon detector just for this reason.

Re: My personal C coding style as of late 2023

#402

Earlier quoted context omitted.

> 2x as many numbers Minor correction, 2^32x as many numbers. Though I agree with your point. Edit: added x to the number for consistency and clarity.

LOL yea, that's what was in my brain but somehow 2x got typed. Good catch.

[deleted]

Re: My personal C coding style as of late 2023

#403

Earlier quoted context omitted.

The reality is that C `int` is 32 bits in size. Sure, that's not true for 16 bit targets. But are you really going to port a 5Mb program to 16 bits? It's not worth worrying about. Your code is highly unlikely to be portable to 16 bits anyway. The problem is with `long`, which is 32 bits on some machines and 64 bits on others. This is just madness. Fortunately, `long long` is always 64 bits, so it makes sense to just…

Choosing integer sizes in C is pretty easy. The standard guarantees certain minimum ranges. 1. Consider the char and short types only if saving storage is important. Do not declare "char number_of_wheels" for a car, just because no car has anywhere near 127 wheels, unless it is really important to get it down to one byte. 2. Prefer signed types to unsigned types, when saving storage is not important. Unsigned types b…

Unsigned doesn’t really bend any rules and their behavior around wraparound is well defined.

Therefore there is another use case : circular buffer indices.

Re: My personal C coding style as of late 2023

#404
post #284
post #251

Earlier quoted context omitted.

> if (need_free == true) > Is such a horrible code smell to me. You have a perfectly good boolean. Why compare it to a second boolean to get a third boolean? > if (need_free) You are probably interested if the `need_free` flag is set to true, and not if `need_free`. It is true that `if (need_free)` has the same behaviour, but it is some steps farther from what you are interested in.

This feels to me like you're introducing the same unnecessary extra layer into your text as in the original code. I mean, why not "You are probably interested in whether it's true that the 'need_free' flag is set to true" leading to > if ((need_free == true) == true) ? Answer: because that extra layer of indirection adds nothing, and just gives you a bit of extra cognitive load and an extra opportunity to make mistak…

[deleted]

Re: My personal C coding style as of late 2023

#405

typedef all structs - yes, helps with conciseness. Use typedefs liberally, I say. But only typedef the things themselves, not pointers to the things. You can always use (type *) when you need a pointer. In particular, for function pointers, typedef the function, not the function pointer. Then you can use the function typedef for function declarations too, which gives you parameter type checking without needing to fix…

> But only typedef the things themselves, not pointers to the things.

I agree with this. One of the things I dislike about SDL_net, etc, is they do exactly what you're describing. It's a pointer but they typedef it as if it's a value type.

I understand the intent but imo that's very icky.

Re: My personal C coding style as of late 2023

#406
post #403

Earlier quoted context omitted.

Choosing integer sizes in C is pretty easy. The standard guarantees certain minimum ranges. 1. Consider the char and short types only if saving storage is important. Do not declare "char number_of_wheels" for a car, just because no car has anywhere near 127 wheels, unless it is really important to get it down to one byte. 2. Prefer signed types to unsigned types, when saving storage is not important. Unsigned types b…

Unsigned doesn’t really bend any rules and their behavior around wraparound is well defined. Therefore there is another use case : circular buffer indices.

Yes it does bend rules. Say that a, b and c are small integers (we don't worry about addition overflow). Given an inequality formula like:

       a 
we can safely perform this derivation (add -b to both sides):

   a - b 
This is not true if a, b and c are unsigned. Or even if just one of them is, depending on which one.

What I mean by "bend the rules of arithmetic" is that if we decrement from zero, we suddenly get a large value.

This is rarely what you want, except in specific circumstances, when you opt into it.

Unsigned tricks with circular buffer indices will not do the right thing unless the circular buffer is power-of-two sized.

Using masking on a poweer-of-two-sized index will work with signed, due to the way two's complement works. For instance, say we hava have [0] to [15] circular buffer. The mask is 15 / 0xF. A negative index like -2 masks to the correct value 14: -2 & 15 == 14. So if we happen to be decrementing we can do this: index = (index - 1) & MASK even if index is int.

Re: My personal C coding style as of late 2023

#407
post #403

Earlier quoted context omitted.

Unsigned doesn’t really bend any rules and their behavior around wraparound is well defined. Therefore there is another use case : circular buffer indices.

Yes it does bend rules. Say that a , b and c are small integers (we don't worry about addition overflow). Given an inequality formula like: a we can safely perform this derivation (add -b to both sides): a - b This is not true if a , b and c are unsigned. Or even if just one of them is, depending on which one. What I mean by "bend the rules of arithmetic" is that if we decrement from zero, we suddenly get a large val…

> What I mean by "bend the rules of arithmetic" is that if we decrement from zero, we suddenly get a large value.

Yes completely consistent with rules of modular arithmetic. A programmer ought to be able to extend math horizons beyond preschool. Which is ironic because I can explain this concept to my 6 year old on a clock face and it’s easy for them to grasp.

> Unsigned tricks with circular buffer indices will not do the right thing unless the circular buffer is power-of-two sized.

How will they “not do the right thing?”. With power of 2 you avoid expensive moduli operations, but nothing breaks if you choose to use a non power of 2.

> two's complement

Two’s complement is not even mandated in C. You are invoking implementation defined behavior here. Meanwhile I can just increment or decrement the unsigned value without even masking the retained value and know the result is well defined.

Like I get 2s complement is the overwhelming case, but why be difficult, why not just use the well defined existing mechanism?

And there’s no tricks here, literally just using the fucking type as it was designed and specified, why clutter things with extra masking.

There’s also the pragmatic atomicity benefit.

Re: My personal C coding style as of late 2023

#408
post #407

Earlier quoted context omitted.

Yes it does bend rules. Say that a , b and c are small integers (we don't worry about addition overflow). Given an inequality formula like: a we can safely perform this derivation (add -b to both sides): a - b This is not true if a , b and c are unsigned. Or even if just one of them is, depending on which one. What I mean by "bend the rules of arithmetic" is that if we decrement from zero, we suddenly get a large val…

> What I mean by "bend the rules of arithmetic" is that if we decrement from zero, we suddenly get a large value. Yes completely consistent with rules of modular arithmetic. A programmer ought to be able to extend math horizons beyond preschool. Which is ironic because I can explain this concept to my 6 year old on a clock face and it’s easy for them to grasp. > Unsigned tricks with circular buffer indices will not d…

In the N3096 working draft it is written: "The sign representation defined in this document is called two’s complement. Previous revisions of this document additionally allowed other sign representations."

Non-two's complement machines are museum relics, and are no longer going to be supported by ISO C.

> why clutter things with extra masking.

Because even if the circular buffer is a power of two, its size doesn't necessarily line up with the range of a given unsigned type.

If the buffer doesn't have a width of 256, 65536, or 4294967296, then you're out of luck; you can't just uint8_t, uint16_t or uint32_t as the circular buffer index without masking to the actual power-of-two size.

(Note that uint16_t and uint8_t promote to int (on the overwhelming majority of platforms where their range fits into that type), so you don't get away from reasoning about signed arithmetic for those.)

Re: My personal C coding style as of late 2023

#409
post #407

Earlier quoted context omitted.

> What I mean by "bend the rules of arithmetic" is that if we decrement from zero, we suddenly get a large value. Yes completely consistent with rules of modular arithmetic. A programmer ought to be able to extend math horizons beyond preschool. Which is ironic because I can explain this concept to my 6 year old on a clock face and it’s easy for them to grasp. > Unsigned tricks with circular buffer indices will not d…

In the N3096 working draft it is written: "The sign representation defined in this document is called two’s complement. Previous revisions of this document additionally allowed other sign representations." Non-two's complement machines are museum relics, and are no longer going to be supported by ISO C. > why clutter things with extra masking. Because even if the circular buffer is a power of two, its size doesn't ne…

So then what is the advantage of using a signed type in this case?

And C++20 already standardized it I know that I already acknowledged this.

Should I go back and rewrite all the old correct code so you feel better?

Re: My personal C coding style as of late 2023

#410

Earlier quoted context omitted.

It’s not great but they’re just aliases so they’re interchangeable, which means you can keep everything consistent within a project and it won’t cause any problems when interacting with outside code

Until you include a header written by someone with the same opinion, and now you get compile errors because they both defined 'u8'. I gotta be honest, all of those style suggestions look good until you try them in a non-solo and non-isolated project, and then you see what a mess you created. We've all been there, as C programmers, and we've all done that in the past, which is why we don't do it anymore

Unless they were defined to completely different types, that shouldn’t be an error
Post reply on HN