Live data from Hacker News

My personal C coding style as of late 2023

nullprogram.com

71–80 of 466 posts

Re: My personal C coding style as of late 2023

#71

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…

I prefer to use typedef's for opaque structs to emulate classes with all private fields, and use 'struct' for plain ol' data structures. Classes should only be accessed via functions, while structs can be accessed directly.

I think this is more-or-less a C/POSIX standard convention. E.g., `pthread_t` vs. `struct stat`.

Re: My personal C coding style as of late 2023

#72

> #define sizeof(x) (size)sizeof(x) Technically, it's illegal to #define over a language keyword.

If you're dead set on doing this, the correct way would be to name the macro in all caps e.g. #define SIZEOF(x) as C is case sensitive. It is somewhat self-documenting to the next guy that SIZEOF() != sizeof().

Any name is fine, as long as it isn't literally "sizeof".

Re: My personal C coding style as of late 2023

#73
post #29

> signed sizes are the way Well, I should probably just say "We're done here." and stop reading the rest of the article. "Signed sizes" are an extremely surprising abstraction break that are just asking for disaster. > No const. It serves no practical role in optimization, and I cannot recall an instance where it caught, or would have caught, a mistake. Should you even be writing C if you haven't hit this? People mix…

> signed sizes are an extremely surprising abstraction break that are just asking for disaster.

Bjarne Stroustrup wrote a detailed memo advocating for signed sizes:

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p14...

Re: My personal C coding style as of late 2023

#74
post #43

> #define sizeof(x) (size)sizeof(x) Undefined behavior[1] > #define assert(c) while (!(c)) __builtin_unreachable() Undefined behavior[1] > I’ll cast away the const if needed. Undefined behavior[2] > The assignments are separated by sequence points, giving them an explicit order. I don't believe assignments are sequence points and only the function call is. [1] https://en.cppreference.com/w/c/language/identifier#Reser…

>> I’ll cast away the const if needed.

> Undefined behavior[2]

How so? As the page you linked mentions, simply casting 'const T *' to regular 'T *' is well-defined; it's only modifying a const object through the pointer that's UB (C17 6.7.3/7).

> I don't believe assignments are sequence points and only the function call is.

Assigments within expressions don't create sequence points. However, the expression of an expression statement is a full expression (i.e., not a subexpression of another expression), and there is a sequence point between each pair of full expressions (C17 6.8/4). In other words, the semicolons create sequence points.

Re: My personal C coding style as of late 2023

#75
post #61
post #43

> #define sizeof(x) (size)sizeof(x) Undefined behavior[1] > #define assert(c) while (!(c)) __builtin_unreachable() Undefined behavior[1] > I’ll cast away the const if needed. Undefined behavior[2] > The assignments are separated by sequence points, giving them an explicit order. I don't believe assignments are sequence points and only the function call is. [1] https://en.cppreference.com/w/c/language/identifier#Reser…

> Undefined behavior[2] Given that this particular undefined behavior usually causes crashes in practice, I expect the author is talking about casting away the const but not actually writing to the pointer. Which is legal.

Or a common situation is mutable -> const -> mutable.

And that is legal.

Re: My personal C coding style as of late 2023

#76

I might just be a grumpy old dev but a lot of this stuff gets an immediate no from me because it’s so unidiomatic. You have to unlearn the accepted way of doing things and you end up with a codebase that is just so foreign to anyone looking at even a small chunk of it, unless they are committed to really learning to do things your way. Everyone knows what a uint32_t is when they see it. The cognitive overhead (until…

The u32, i8, etc type aliases are the least offensive parts of this to me, even though I rarely see them in C code. I think those are pretty clear.

b32, size (ptrdiff_t), usize (size_t), nothing for ssize_t... what? Those are unidiomatic and also kind of weird. The macros... some are fine, some are weird.

If this makes the author more productive in C, it might behoove them to see if a higher level language like Rust would meet their needs.

Re: My personal C coding style as of late 2023

#77
post #67
post #61

Earlier quoted context omitted.

> Undefined behavior[2] Given that this particular undefined behavior usually causes crashes in practice, I expect the author is talking about casting away the const but not actually writing to the pointer. Which is legal.

The legal cases in which he needs to cast away const could be avoided if the arguments to called functions were appropriately qualified.

He never said he needs to cast away const to do what he is attempting to do, he just said that he wants to cast away const to reduce clutter, even though the program would have the same semantics as if he kept the const.

Re: My personal C coding style as of late 2023

#78
Parameters and functions

No const.

Please don't. `const` is incredibly valuable, not only to the reader, but to the compiler.

Take for example:

  int Foo_bar(Foo const* self);
Just looking at this signature, I know that calling `bar()` will not modify the state of the object. This is incredibly valuable information to the reader.

Furthermore, if I want to create a `Foo` constant, I can only call this function if it is `const`.

  static Foo const a_foo = FOO_INIT(&some_params);
  return Foo_bar(&a_foo); // Will not compile without 'const' in function
`const` is valuable to the compiler, since `a_foo` can be placed into ROM on some platforms like MCUs, saving precious RAM.

Re: My personal C coding style as of late 2023

#79
post #78

Parameters and functions No const. Please don't. `const` is incredibly valuable, not only to the reader, but to the compiler. Take for example: int Foo_bar(Foo const* self); Just looking at this signature, I know that calling `bar()` will not modify the state of the object. This is incredibly valuable information to the reader. Furthermore, if I want to create a `Foo` constant, I can only call this function if it is…

Agreed; const is one of those features that is so good I wish a lot of other languages (e.g. java) had it.

Re: My personal C coding style as of late 2023

#80
post #63

Earlier quoted context omitted.

This is the use case for `uint_fast8_t` (part of the C99 standard); it should use whatever width of unsigned integer is enough to store a byte, but fastest for the platform. You always know that the type can be serialized as 8 bits, but it might be larger in memory. So long as you don't assume too much about your struct sizes across platforms, it should be a good choice for this. Although, if alignment is an issue, i…

10 years ago when ATmegas were still around and your 32 bit variable was generating 3 instructions for addition I would say „right on“ but now everything is a 32 bit Cortex-M and please stop polluting your code with this nonsense

IDK it seems semantically right
Post reply on HN