u/ElementWiseBitCast

My opinions about code style

I disagree with most people about code style.

In code that is just for myself, I actively avoid structs, unions, pointers, floating point numbers, dynamic memory allocation, for loops, threading, typedefs, and most of the standard library. The reason is that I strongly dislike debugging, and I would rather spend more time writing code and less time debugging it. Additionally, I compile with many warning flags that are not included in the common -Wall -Wextra -Wpedantic.

Furthermore, I litter code that is just for myself with a macro that is almost like assert, yet instead of expanding to nothing if NDEBUG is defined, it expands to nothing if EBUG is not defined. That enables me to pass -DEBUG to GCC to compile a debug build. Since the macro expands to nothing when EBUG is not defined, there is no penalty for optimized builds. Since I do not use "debuggers", -Og is not needed for a debug build of code that is only for me.

Additionally, I limit myself to C89 (aka C90) whenever I am working on something small for myself. (I use the -ansi and -Wpedantic GCC flags to help enforce this.) The reason is that I simply do not find the vast majority of the features introduced since then to be useful.

I figure that if I am not going to use any of the features anyway, then it is probably a mistake if I do accidentally use one. Once a program gets large enough, then I may eventually find myself wanting to use a newer feature, like long long, restrict, _Noreturn, etc. However, I use C89 unless I have a reason not to.

Honestly, although no-one seems to agree with me on this, I find global variables to be significantly better than passing massive structs and many pointers around the place, like most people do. In my own experience, I have found myself to make fewer mistakes when working with global variables than when working with structs and pointers, even when the structs are kept small. Another thing that I find to be an absolute non-problem is goto statements. I prefer using goto statements over sacrificing maintainability by having a mess of if statements and and extra variables, which is sometimes needed if you are dogmatically insisting on avoiding a goto statement.

I like to declare function parameters const, including scalars, and I like to have functions return only at the end. If I feel the need to have another exit point, and the code is for myself, then I will typically use a goto statement with a label at the end (and possibly a null statement if the function is void and I am using C89). I do this because it is easier to refactor code when the parameters are const and there is a single exit point.

When comparing things, I always use < and >=, yet never > or <=. The reason is that it is trivial to replace one direction of a comparison with the other, and < is not likely to be confused with >=, because they point opposite directions.

I dislike small functions. I prefer medium sized functions. The reason is that I find that having many functions makes it more difficult to mentally understand the control flow of a piece of a program. If a function is less than a screen of text, then I probably consider it to be too small. Having large functions can make it more difficult, as well, due to deep nesting. Thus, a happy medium is the best.

I avoid storing boolean values into variables or passing them to functions. If it is annoying to avoid them, then I refactor my code. Also, if an integer fits in a `signed char` or an `unsigned char`, then I will use store it as that, even if it slightly hurts performance in some cases. If an integer is never negative, then I will store it as an unsigned integer, even if it slightly hurts performance in some cases.

Another thing that I disagree with most people about is error handling. When writing code that is only for myself, I typically handle errors by calling exit(1);and printing a message if it is a debug build (EBUG). Most other people think that this is insane. However, I find that it reduces debugging time.

I use either astyle with a configuration file or GNU indent with -kr to format my code, and I use cppcheck with --enable=all to lint my code.

When working on something that compiles reasonably quickly, I compile my code frequently when making changes to ensure that it still works on basic cases, so that I do not need to spend as much time trying to figure out what change broke the code. However, if the code compiles slowly, then I do not compile frequently.

I do not use version control when working on something that is only a few files. Instead, I occasionally make a backup file of a known working version of whatever file I am working on. I never use "debuggers" when debugging. I do not find debuggers to be useful, ever. However, I use valgrind, and I have found it to be useful, even though it makes code run very slowly during debugging.

Another thing that I disagree with many people on is that I think that fewer larger files is often more easily understood than a large amount of tiny files.

Unfortunately, when I am working on code that is not just for myself, I do not always have a choice about stylistic choices, and I am sometimes forced to do dumb things like pass massive structs everywhere and use malloc to allocate space for an array that has a size that is a compile time constant. Furthermore, attempting to compile code that is not written by me with all of the warnings and lints that I prefer yields so many warnings that it is not remotely worth fixing. In addition, the code quality of the code that I write often degrades by a large amount when I am trying to meet a deadline, because the short term is prioritized over the long term.

reddit.com
u/ElementWiseBitCast — 3 days ago