Live data from Hacker News

Principles for C programming

drewdevault.com

51–60 of 149 posts

Re: Principles for C programming

#51

Avoid magic. Do not use macros. Disagree. Use magic, especially macros, in ways such that your code becomes easier, not harder, to understand . A few examples from my own code: 1. My "elastic arrays" ( https://github.com/Tarsnap/libcperciva/blob/master/datastruc... and .c) allow me to write ELASTICARRAY_DECL(STRLIST, strlist, const char *); and get a data structure STRLIST which contains an arbitrary number of string…

It's worth keeping in mind that making stuff more maintainable for you does not necessarily make it more maintainable for others.

It's nice if your successor can just use your abstractions, but if he needs to modify them ...

Re: Principles for C programming

#52
post #3

Feels too heavy on "donts." I imagine the motivation the desire to be heard and understood. But I also need something simple, like "keep it simple, stupid" or "first have a working product that anyone could read". Positivity >> negativity.

Think of a circle with a dot at the center.

When you define things positively - "do this, do that" - you're saying "get to the center dot, and come from anywhere on the circle".

When you define things negatively - "don't do this, don't do that" - you're saying "get to anywhere on the circle, and come from the dot."

"Test your code". Your code could be library code, it could be core language features, it could be framework patterns, it could be executable utilities. Ends up all the same - tested code. From anywhere, to somewhere specific.

"Don't test controller actions". You can test requests, you can test at a feature level, you can test the models and functions used by the controllers. Ends up all kinds of different - no tested controllers. From somewhere specific, to anywhere.

Something telling to do or not do something doesn't mean it's positive or negative; that comes from tone and presentation, not content.

Re: Principles for C programming

#53
post #51

Avoid magic. Do not use macros. Disagree. Use magic, especially macros, in ways such that your code becomes easier, not harder, to understand . A few examples from my own code: 1. My "elastic arrays" ( https://github.com/Tarsnap/libcperciva/blob/master/datastruc... and .c) allow me to write ELASTICARRAY_DECL(STRLIST, strlist, const char *); and get a data structure STRLIST which contains an arbitrary number of string…

It's worth keeping in mind that making stuff more maintainable for you does not necessarily make it more maintainable for others. It's nice if your successor can just use your abstractions, but if he needs to modify them ...

True. That's why I'm hoping more people will start using these.

Re: Principles for C programming

#54

I disagree with quite a few of them. The title should be "Principle for C programming ON UNUX BASED SYSTEMS". C programming is quite a bit wider that this, and some of the typical points here are no-no if you want to write /portable/ C. For example, "Do not use fixed size buffers". It's all very fine, but 1) it can be exploited as well if someone managed to fudge the size you are going to allocate, and 2) on some pla…

> For example, "Do not use fixed size buffers". It's all very fine, but 1) it can be exploited as well if someone managed to fudge the size you are going to allocate

Fuzzing really underscored just how terrible "dynamically sized buffers" are to me as well. Even if your logic is perfectly correct (e.g. no possibility of buffer overflows), something as simple as deserializing a length-prefixed array needs a quota or cap. It's not enough to handle malloc failing: Someone will successfully allocate 1.9GB via your 32-bit deserialization code, spreading the actual allocation failures across the rest of your codebase - including all 3rd party and system libraries - most of which almost certainly have at least one oversight in OOM condition error handling, invoking all kinds of potentially exploitable undefined behavior.

Re: Principles for C programming

#55

Earlier quoted context omitted.

To be honest I would just have your library offer a function that does it your fancy way. It's not possible to have a single function do this. Not possible to have any finite number of functions do this if, like me, you want to support all floating-point and integer types. Self-contained routines that are completely unmaintainable and unintelligible to anyone but you, though. All of my macros are intelligible to anyo…

>It's not possible to have a single function do this. Not possible to have any finite number of functions do this if, like me, you want to support all floating-point and integer types. Just tack an 'i' or 'f' or 'l' on the end. Not a big deal. Literally one extra character. And you don't have to hold shift the whole time. >All of my macros are intelligible to anyone who understands the C preprocessor. I understand th…

Just take an 'i' or 'f' or 'l' on the end. Not a big deal. Literally one extra character.

I don't think you understand. At a minimum, you would need parsenumi, parsenuml, parsenumll, parsenumimax, parsenumu, parsenumul, parsenumull, parsenumumax, parsenumi8, parsenumi16, parsenumi32, parsenumi64, parsenumu8, parsenumu16, parsenumu32, parsenumu64, parsenumf, and parsenumd.

All code is liable to use an outdated syntax or features in 10 years. What if the stdlib does improve and adds functions that supplant these? What if they do so only partially? What if your functions could be improved to rely on a new stdlib function that's safer/faster/etc?

This is C, not perl. Features don't become "outdated" in a mere 10 years. And if there is a new standard library function which is useful here... well, (a) I wouldn't want to use it for at least 20 years, and (b) I'd probably be one of the people writing said standard library function, so I'd have no difficulty updating my macros.

Re: Principles for C programming

#56

I disagree with quite a few of them. The title should be "Principle for C programming ON UNUX BASED SYSTEMS". C programming is quite a bit wider that this, and some of the typical points here are no-no if you want to write /portable/ C. For example, "Do not use fixed size buffers". It's all very fine, but 1) it can be exploited as well if someone managed to fudge the size you are going to allocate, and 2) on some pla…

I used to typedef my structs but I stopped doing that a while ago. Even if something is an opaque type it's still useful to know that it's a struct and not some random typedef for an integer or similar. You might not be able to copy it for instance, and if you can you might not want it if it turns out to be a few kilobytes in size and harms performance.

The linux kernel coding style in particular forbids such typedefs: https://www.kernel.org/doc/html/latest/process/coding-style....

I don't agree with everything in the kernel coding style but it's mostly reasonable and I think their approach to typedefs is perfectly reasonable.

And why do you use separate typedefs for pointer types? That's borderline obfuscation IMO, if I'm dealing with a pointer I want to know it. If it's in order to save a single keystroke it really isn't worth it IMO and I don't see how it helps reworking anything.

I agree with the fixed size buffer thing though. There are plenty of situations where fixed size buffers are completely fine, that's way too broad as a general "principle". I guess the idea is "make sure you don't reserve less memory than you need" but that's rather obvious, isn't it?

Re: Principles for C programming

#57
> Use only standard features. Do not assume the platform is Linux

I'll decide what platform I am targeting, thank you. I don't feel any obligation to support obscure OSes if I am just targeting linux. I might as well use useful linux-specific and GNU userland features, they are helpful.

Re: Principles for C programming

#58

Earlier quoted context omitted.

>It's not possible to have a single function do this. Not possible to have any finite number of functions do this if, like me, you want to support all floating-point and integer types. Just tack an 'i' or 'f' or 'l' on the end. Not a big deal. Literally one extra character. And you don't have to hold shift the whole time. >All of my macros are intelligible to anyone who understands the C preprocessor. I understand th…

Just take an 'i' or 'f' or 'l' on the end. Not a big deal. Literally one extra character. I don't think you understand. At a minimum, you would need parsenumi, parsenuml, parsenumll, parsenumimax, parsenumu, parsenumul, parsenumull, parsenumumax, parsenumi8, parsenumi16, parsenumi32, parsenumi64, parsenumu8, parsenumu16, parsenumu32, parsenumu64, parsenumf, and parsenumd. All code is liable to use an outdated syntax…

>I don't think you understand. At a minimum, you would need parsenumi, parsenuml, parsenumll, parsenumimax, parsenumu, parsenumul, parsenumull, parsenumumax, parsenumi8, parsenumi16, parsenumi32, parsenumi64, parsenumu8, parsenumu16, parsenumu32, parsenumu64, parsenumf, and parsenumd.

Fair. I still don't really see the value in this, though. The only real gain is from doing the range check, and that's niche enough that I'd just write a function for the particular project that demands it, and I'd only have to write one function because there'd likely only be one integer type it's relevant to.

>This is C, not perl. Features don't become "outdated" in a mere 10 years. And if there is a new standard library function which is useful here... well, (a) I wouldn't want to use it for at least 20 years

Fair enough.

>I'd probably be one of the people writing said standard library function

I hope not!

Re: Principles for C programming

#59

Earlier quoted context omitted.

To be honest I would just have your library offer a function that does it your fancy way. I agree that there could be better integer parsing functions, I disagree that they should be macros. >Not at all. The point is to have self-contained routines which Just Work in order to ensure that the rest of the code is easier to read and maintain. Self-contained routines that are completely unmaintainable and unintelligible…

To be honest I would just have your library offer a function that does it your fancy way. It's not possible to have a single function do this. Not possible to have any finite number of functions do this if, like me, you want to support all floating-point and integer types. Self-contained routines that are completely unmaintainable and unintelligible to anyone but you, though. All of my macros are intelligible to anyo…

> More to the point, why do they need to be maintainable? When was the last time you maintained the strtof function in your C library?

A few years ago. https://sourceware.org/bugzilla/show_bug.cgi?id=15744

Acting like you can get anything done right in C simply because it's self-contained is proven wrong every day. It's good practice, yes, but doesn't magically (we like this word now) make us immune to error. Everything needs to be maintainable, even if it is proven to be correct, for the simple reason that we can't just replace broken pieces of code with the same simplicity we can replace a broken fridge.

Also, if there's anything we know about code, is that we are constantly trying to invent new ways to expose it to a new interface - thereby breaking it.

Post reply on HN