Live data from Hacker News

Principles for C programming

drewdevault.com

11–20 of 149 posts

Re: Principles for C programming

#11
post #6

Earlier quoted context omitted.

I'd say that's a bit naive. How would you go about writing something like rsyslog without doing the things they have done? How would you create rsyslog's flexible (I'm not saying it's "good") module system where people can write their own pluggable custom input/output modules? Your comment somehow suggests that it's possible to achieve everything they have achieved in terms of functionality while doing it in a much m…

Are you serious? You could start by fixing that godawful code style and removing the macros. You could change these variable names and function names to make more sense (CHKiRet? omsdRegCFSLineHdlr? What the hell?). The compiler extensions are unnecessary and can just be removed. None of these changes have any impact on the functionality of rsyslog.

Cool down a bit, would you?

You could get your point across without using that tone.

Re: Principles for C programming

#12
post #5
post #4

All sounds good in theory but in practice in a large enough project many of the suggestions are not practical. Recently I was looking at rsyslog's source code. Look at this "simple" file for example, https://github.com/rsyslog/rsyslog/blob/master/plugins/omstd... It's an output module for rsyslog that logs to stdout. I wanted to gouge my eyes out.

This code fails to follow many of my suggestions. - Liberal use of macros - Horribly unreadable coding style - Needless use of compiler extensions - Very poorly organized code This is awful code because the authors are morons, not because the language is bad. They could stand to read this blog post.

I did find this line of code quite entertaining:

     if((r = write(1, toWrite, len)) != (int) len) { /* 1 is stdout! */
If you're going to go to the effort to add the comment, why not just use stdout instead of 1?

Re: Principles for C programming

#13
One thing that comes to mind is that young people today are weaned on oo languages and may find it hard to adopt the good old-fashioned non-oo style typical for C.

For example, intrusive data structures may seem like an anti-pattern to oo programmers, while they feel perfectly ok for a C programmer. On the contrary, C programmer may find non-intrusive data structures to be an anti-pattern as they require extra memory allocations.

Re: Principles for C programming

#14
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 platform, you don't have/want malloc(). So it's a lot better to have a fixed buffer and check the sizes carefully before copying into it.

Another one I dislike (but it's personal preference) is the 'use struct for pointers to structs' -- well, nope, I don't like that, it's unnecessarily heavy. I typedef my structs all the time, and call them something_t, and * something_p. It's easier to rework, rename, search for and it's quicker to type so makes the source code lighter to read. I know it's not popular, and for example the kernel guidelines agree with you, but I don't.

As for "no circumstances should you ever use gcc extensions or glibc extensions" well sorry, I also disagree here. I love the 'case X..Y:' syntax for example and it's been around for about a million years. It's not because the C standards prefer adding idiotic syntax instead of useful ones like this that I'm going to stick along and limp when there is a perfectly nice, clear and very readable alternative.

Another one I love but can't use are the sub-functions. Now what also would have been a lovely extension if the runtime had been perfected a bit, but it was never 'finished'. Speak of easier code to read when your qsort() callback is listed /just above/ the call to qsort().

Another extension is of course the __builtins that you actually do need on modern systems. Like memory barriers, compare and swaps, ffs, popcount and so on. Of course I can have an explicit function to do it (in the case of the last 2), but that's the sort of things that ought to be in the C library anyway. So I'll use these, thanks.

As far as the rest of the article about the process, your code reviewers and so on, in many places and on many projects (open source ones are a case in point) you don't have the freedom/time to do that. The rule is ' do as best as you can' -- and that ought to do it in many cases.

Re: Principles for C programming

#15
interesting points. the maintainability part is freaking important but i guess you truly realize it only when you got bitten by it several times. some other details i don't necessarily agree with, like buffer sizes if you program for embedded devices or if you have real-time constraints.

Re: Principles for C programming

#16

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…

It's quite common in Embedded programming to use pools of fixed size buffers. Malloc/free work on these pools.

Re: Principles for C programming

#17

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, and 2) on some platform, you don't have/want malloc(). So it's a lot better to have a fixed buffer and check the sizes carefully before copying into it.

This is reasonable. I mentioned measuring fixed size buffers if you have to use them, but edited it out. I think all programming guidelines should be taken with a grain of salt and adjusted as necessary when sanity demands deviations from them.

>Another one I dislike (but it's personal preference) is the 'use struct for pointers to structs' -- well, nope, I don't like that, it's unnecessarily heavy. I typedef my structs all the time, and call them something_t, and * something_p. It's easier to rework, rename, search for and it's quicker to type so makes the source code lighter to read. I know it's not popular, and for example the kernel guidelines agree with you, but I don't.

It's easier to rework, rename, and search for? How so? The problems with it is that you should be able to easily differentiate structs and scalars, becuase you should treat them differently. Same for pointers. You should generally be passing structs by reference, not by value, for example. I don't appreciate hiding information about the nature of your types for the sake of ergonomics. The readability gain trumps the extra quarter-second of typing each time you use the type.

>As for "no circumstances should you ever use gcc extensions or glibc extensions" well sorry, I also disagree here. I love the 'case X..Y:' syntax for example and it's been around for about a million years. It's not because the C standards prefer adding idiotic syntax instead of useful ones like this that I'm going to stick along and limp when there is a perfectly nice, clear and very readable alternative.

gcc is not the only compiler in the world. You can't be crying out about the Unix-specific nature of this article and then favor a dependence on gcc.

>Another one I love but can't use are the sub-functions. Now what also would have been a lovely extension if the runtime had been perfected a bit, but it was never 'finished'. Speak of easier code to read when your qsort() callback is listed /just above/ the call to qsort().

Ugh. Just make a static function.

>Another extension is of course the __builtins that you actually do need on modern systems. Like memory barriers, compare and swaps, ffs, popcount and so on. Of course I can have an explicit function to do it (in the case of the last 2), but that's the sort of things that ought to be in the C library anyway. So I'll use these, thanks.

Why do you need these? If you must, see my comments on abstracting non-standard/non-portable/etc code.

Re: Principles for C programming

#18
post #6

Earlier quoted context omitted.

I'd say that's a bit naive. How would you go about writing something like rsyslog without doing the things they have done? How would you create rsyslog's flexible (I'm not saying it's "good") module system where people can write their own pluggable custom input/output modules? Your comment somehow suggests that it's possible to achieve everything they have achieved in terms of functionality while doing it in a much m…

Are you serious? You could start by fixing that godawful code style and removing the macros. You could change these variable names and function names to make more sense (CHKiRet? omsdRegCFSLineHdlr? What the hell?). The compiler extensions are unnecessary and can just be removed. None of these changes have any impact on the functionality of rsyslog.

Maybe you are not too familiar with rsyslog. Those are modules that get compiled into rsyslog itself.

If you attempted to create such a module system you will very soon see that doing a lot of the things that they have done is unavoidable (weird naming and so on aside).

I see this attitude where people suggest that writing beautiful secure wonderful C code is possible however just somehow all people are just too dumb to be able to do it.

Every example you show them they say "nah, that person? also too dumb".

You can find similar crap like that example that I pasted in all popular C projects including the Linux kernel and Redis.

At some point does something become not fit for purpose?

I'd say we'd make more progress if we become less tolerant of technologies that disrespect us as humans.

If only an elite subset of people are good enough to program in C. I'd say that's because C is not good enough, not because everyone else is too bad for C.

Post reply on HN