From my own projects, I have noticed a trend – code is never consistently styled. I change my own coding style every once in a while, so over the years I notice a siginificant change in source code – even within the same project! I am of the opinion that syntax is not that important, but it is offputting when you see different conventions, and you want to make them consistent. I ended up spending a lot of time restyling old code to match my new conventions – time I should be spending writing games.
Recently I did a bit of programming in go and I liked their approach to this problem. Go provides a tool called gofmt which automatically styles source code to the de facto go code style. This means all go programs ending up looking fairly consistent.
This looked pretty cool to me, but I do most of my programming in C/C#/python. There is a standard for styling python programs called pep8 which solves this problem nicely, and pylint will help keep you close to the standard.
For C and C#, there does not seem to be any canonical formatting style (Microsoft do give some guidelines on style for C#, but I don’t know of any free tool which enforces these – please comment if you do).The wikipedia page on indentation style alone gives many options for arranging curly braces, all with their own advantages and disadvantages. None of them match with what I consider good style either.
In the absence of a standard, we can come up with our own. As long as we are consistent with the standard, there is no problem. So we need a tool which will style our code to this specification. I found 2 free tools which do this :
Both of them are good tools, but astyle had more options I cared about and supports both C and C#, so I went with that. After half an hour of experimenting with options I eventually came to this line to format a C file:
|
1 2 3 4 |
astyle --style=java --suffix=.astyleorig --unpad-paren \ --delete-empty-lines --add-brackets --convert-tabs \ --align-pointer=type --lineend=linux --suffix=none \ --indent-switches main.c |
Now I put this into a bash script called ”enforce_coding_style.sh” in the root of my repo to style all of our source files:
|
1 2 3 4 5 6 7 |
#!/bin/bash find . \( -name '*.c' -o -name '*.h' \) -exec \ printf "Indenting file {}\n" \; -exec \ astyle --style=java --suffix=.astyleorig \ --unpad-paren --delete-empty-lines --add-brackets \ --convert-tabs --align-pointer=type --lineend=linux \ --suffix=none --indent-switches {} \; |
This will also force unix line endings which is nice. So that we never have to worry about the problem again, we can call this script from a git pre-commit hook in our repo “.git/hooks/pre-commit”:
|
1 |
bash ./enforce_coding_style.sh |
Make sure everyone who uses the project has this enabled, and your code will look consistent forever more. If you ever want to update the standard, you just need to update the options passed to astyle in the bash script.
Update:
Improved bash script thanks to feedback from claudius on hacker news.
I suggest you use clang-format (http://clang.llvm.org/docs/ClangFormat.html). It’s a new clang-based formatter, which makes it way more powerful than astyle because clang actually fully parses your source. It’s also a new, actively maintained project.
Sounds awesome, will totally look at this.
We also settled on astyle for C formatting on our projects. It seems to do a very good job without much hassle. Just a small note, the script seems to have the shell list file, then pass that to ls, then read the files back in, which is a redundant step and also troublesome if a space ever ends up in a file name (seems unlikely though), so I would generally do:
for file in "${basedir}"/*.[ch]
Yep thanks for the tip!
I’ve updated the post to use find with the -exec option which I think is a bit nicer than the for loop.
Yup, formatting as a pre-commit hook is the way to go. That said, I’ve never seen a style guide that gives any sensible advice on how to break long lines (e.g. function calls with many and long argument expressions).
Also check out the ClangFormat, which is part of the upcoming Clang 3.3: http://clang.llvm.org/docs/ClangFormat.html
GNU indent has some nice options for breaking up large lines sensibly : https://www.gnu.org/software/indent/manual/indent.html#SEC12
Just wanted to drop a line to mention StyleCop (http://en.wikipedia.org/wiki/StyleCop).
Although I haven’t used it, your formatting discussion brought to mind an old tool called FxCop (http://en.wikipedia.org/wiki/FxCop) which I knew wasn’t right, but did automate checks for MSIL compatibility.
They might prove helpful, though it sounds like you’ve already found a working solution.
(These tools don’t hit standard C either, but it’s a start…)
StyleCop would be the closest thing to pylint for C#. http://stylecop.codeplex.com/
The bash script seems not to be very efficient, as it applies astyle on each file before each commit. Looking through git history can be helpful to avoid checking every files, but only changes. Something like this one.
You can use StyleCop for C#
I think you are kind of harsh towards indent, or maybe you don’t have the real indent (GNU indent). It is a pain in the neck until you have configured it properly so be sure to work on backups.
There are both GNU, linux and other coding styles available there, you can tinker it to pretty much your own will, if you care to read the man pages, and figure them out while you figure out how you want your source to be formatted.
For more about formatting source code I recommend reading the GNU coding standard, freely available in various formats from GNU.org
(Thank you GNU!)
I was definitely too dismissive of indent in my post – I actually used indent on the first version of this script. And I did read the man page and had it set up fairly well. The 2 reasons I switched were :
1) GNU indent did not support my preferred style of pointer declaration (I prefer “int* a” rather than “int *a”) whereas astyle allowed both.
2) astyle supports C# as well.
Astyle supports even more coding styles than indent as well, which made it a fairly easy choice.