11 ms·
Consistently Formatting C
- JasonFruit 14y agoHaving it as a git pre-commit hook seems dangerous to me — what if there's a bug in the formatting tool that breaks something in the code? Then you have non-functioning code committed. It's a lot better if you can just have the self-discipline to run the formatter when you're done making changes. Alternatively, you could have it in your build script, so you'll likely catch the formatter-related problem when you're testing your code.
- myg204 14y agoor have it run every time you save a file
- wging 14y agoOr what about a pre-commit hook that, instead of transforming the version you're committing, just compares a transformed version to the version you're trying to commit? You could warn on commit if they don't match, plus maybe provide an option to override the warning and commit anyway.
- df3n5 14y agoI like this. If someone writes a version which does this let me know and I'll post a link on the post.
- deleted 14y ago[deleted]
- super_mario 14y agoYou are better off putting your options into .astylerc. This is what I have in mine: # Use K&R formatting style style=kr # Indent class and struct blocks so that the blocks 'public', 'private' and # 'protected' are indented. This option is effective in C++ files only indent-classes # Indent 'switch' blocks so that the 'case X:' statements are indented with # the switch block. The entire case block is indented. # # For example: # switch (foo) # { # case 1: # a += 1; # break; # # case 2: # { # a += 2; # break; # } # } # # becomes # # switch (foo) # { # case 1: # a += 1; # break; # # case 2: # { # a += 2; # break; # } # } #indent-switches # Indent C++ namespaces (this option has no effect on other file types) # Add extra indentation to namespace blocks. # For example: # namespace foospace # { # class Foo # { # public: # Foo(); # virtual ~Foo(); # }; # } # # becomes # # namespace foospace # { # class Foo # { # public: # Foo(); # virtual ~Foo(); # }; # } indent-namespaces # Indent multi line preprocessor definitions ending with a backslash # For example: # # #define Is_Bar(arg,a,b) \ # (Is_Foo((arg), (a)) \ # || Is_Foo((arg), (b))) # # becomes: # # #define Is_Bar(arg,a,b) \ # (Is_Foo((arg), (a)) \ # || Is_Foo((arg), (b))) # indent-preprocessor # Indent C++ comments beginning in column one. # For example # # void Foo()\n" # { # // comment # if (isFoo) # bar(); # } # # becomes: # # void Foo()\n" # { # // comment # if (isFoo) # bar(); # } # indent-col1-comments # Pad empty lines around header blocks (e.g. 'if', 'for', 'while'...). # # isFoo = true; # if (isFoo) { # bar(); # } else { # anotherBar(); # } # isBar = false; # # becomes: # # isFoo = true; # # if (isFoo) { # bar(); # } else { # anotherBar(); # } # # isBar = false; # break-blocks # Insert space padding around operators. Any end of line comments will remain # in the original column, if possible. Note that there is no option to unpad. # Once padded, they stay padded. # # if (foo==2) # a=bar((b-c)*a,d--); # # becomes: # # if (foo == 2) # a = bar((b - c) * a, d--); # pad-oper # Insert space padding after paren headers only (e.g. 'if', 'for', 'while'...). # Any end of line comments will remain in the original column, if possible. # This can be used with unpad-paren to remove unwanted spaces. # # if(isFoo(a, b)) # bar(a, b); # # becomes: # # if (isFoo(a, b)) # bar(a, b); # pad-header # Remove extra space padding around parenthesis on the inside and outside. Any # end of line comments will remain in the original column, if possible. This # option can be used in combination with the paren padding options pad‑paren, # pad‑paren‑out, pad‑paren‑in, and pad‑header above. Only padding that has not # been requested by other options will be removed. # # For example, if a source has parens padded on both the inside and outside, # and you want inside only. You need to use unpad-paren to remove the outside # padding, and pad‑paren‑in to retain the inside padding. Using only # pad‑paren‑in would not remove the outside padding. # # if ( isFoo( a, b ) ) # bar ( a, b ); # # becomes (with no padding option requested): # # if(isFoo(a, b)) # bar(a, b); # unpad-paren # Delete empty lines within a function or method. Empty lines outside of # functions or methods are NOT deleted. If used with break-blocks or # break-blocks=all it will delete all lines EXCEPT the lines added by the # break-blocks options. # # void Foo() # { # # foo1 = 1; # # foo2 = 2; # # } # # becomes: # # void Foo() # { # foo1 = 1; # foo2 = 2; # } # delete-empty-lines # Attach a pointer or reference operator (* or &) to either the variable type # (left) or variable name (right), or place it between the type and name # (middle). The spacing between the type and name will be preserved, if # possible. To format references separately use the following align-reference # option. # # char *foo1; # char &foo2; # # becomes (with align-pointer=type): # # char* foo1; # char& foo2; # # char* foo1; # char& foo2; # # becomes (with align-pointer=middle): # # char * foo1; # char & foo2; # # char* foo1; # char& foo2; # # becomes (with align-pointer=name): # # char *foo1; # char &foo2; # align-pointer=name # Set the minimal indent that is added when a header is built of multiple # lines. This indent helps to easily separate the header from the command # statements that follow. The value for # indicates a number of indents and is # a minimum value. The indent may be greater to align with the data on the # previous line. # The valid values are: # 0 - no minimal indent. The lines will be aligned with the paren on the # preceding line. # 1 - indent at least one additional indent. # 2 - indent at least two additional indents. # 3 - indent at least one-half an additional indent. This is intended for large # indents (e.g. 8). # # The default value is 2, two additional indents. # # // default setting makes this non-bracketed code clear # if (a < b # || c > d) # foo++; # # // but creates an exaggerated indent in this bracketed code # if (a < b # || c > d) # { # foo++; # } # # becomes (when setting --min-conditional-indent=0): # # // setting makes this non-bracketed code less clear # if (a < b # || c > d) # foo++; # # // but makes this bracketed code clearer # if (a < b # || c > d) # { # foo++; # } # min-conditional-indent=0 # Set the maximum of # spaces to indent a continuation line. The # indicates # a number of columns and must not be greater than 120. If no # is set, the # default value of 40 will be used. A maximum of less than two indent lengths # will be ignored. This option will prevent continuation lines from extending # too far to the right. Setting a larger value will allow the code to be # extended further to the right. # # fooArray[] = { red, # green, # blue }; # # fooFunction(barArg1, # barArg2, # barArg3); # # becomes (with larger value): # # fooArray[] = { red, # green, # blue }; # # fooFunction(barArg1, # barArg2, # barArg3); # max-instatement-indent=9
- wging 14y agoDo you mean to have indent-switches commented out?
- super_mario 14y agoYes :D.
- blaabjerg 14y agoFreak!
- taeric 14y agoThis is great, except for the times that you take advantage of the fact that programming is essentially ascii art sometimes. I grant that these examples are edge case in occurrence, but breaking the formatting really helps there. And... I just can't bring myself to think that a rigid adherence to formatting will benefit any codebase as much as folks would like to think. As "edge case" as my reasons for wanting to break it, the straw men built up to show why it matters are even more ridiculous. And this is completely ignoring that, once again, the largest collaboratively maintained source tree on the planet (that I am aware of) does not need this level of formatting adherence. Why do we think other projects do?
- to3m 14y agoI've not noticed any correlation either. If it's actually useful, which it may be, the degree of usefulness seems to be slight enough that it just gets lost in the noise. I guess people like this stuff because it's easy to check for, and easy to explain, and everybody's been annoyed by inconsistent code layout before, to one extent or another, so it can be an easy sell. It might also function as starter rules, getting a wayward team used to the simple idea of all working the same way, something that can be further extended in the future with more rigorous rule sets. It must be something like that, anyway, because I have to say that it doesn't seem to do anything for the actual quality of the code. I've torn my hair out in frustration over beautifully consistent code just as much as I have over the stuff that looks like a test case for a C parser - and it's precious little consolation if the stupid braces are in the same place on every line.
- df3n5 14y agoThis is true - there is a definite distinction that should be made between style and code quality. Good code could be ofuscated and it would still be good code. I don't think converting bad quality code to good quality code is something that can be automated. It should be something that is caught by code review and be flagged for discussion with the whole team if it is a general anti-pattern which is emerging in the codebase. When patterns / anti-patterns are observed, I think they should be called out and documented for future reference. This over time will lead to general coding guidelines, which are way more important than consistent syntax, as they should mitigate the hair pulling sessions you describe.
- chris_engel 14y agoHah. I thought the article was about cleaning harddrives :D
- claudius 14y agoThat Bash script looks a little irky…just imagine more than one level of directories, and `` is both none-portable and overly ugly, at least compared with $()…not to mention that Shell expansion (for i in $basedir/⁕.{c,h}) should work equally well :) Anyway, I would rather suggest something like: find . \( -name '*.c' -o -name '*.h' \) -exec printf "Doing Stuff on {}\n" \; -exec head -n 1 {} \;
- df3n5 14y agoYour bash foo eclipses mine, thank you for the bash schooling! I've updated the script on my original post and gave you credit, hope that's okay.
- claudius 14y agoSure, feel free to do whatever you like with that. Bash is more or less the only scripting language I know/use, so it is only natural to find shortcuts over the years :)
- df3n5 14y agoThanks! :D
- csense 14y ago> Bash is more or less the only scripting language I know/use I feel sorry for you. Try Python, especially if you're doing anything involving string processing.
- claudius 14y agoThanks, but I used Python once for a little FUSE module (long story…) and didn’t particularly like it. If anything, I’d rather try Perl - but then, you can do so much with a sensible Shell and the coreutils, the need to even write a proper script rather than a large concatenation of pipes is a rare event for me. So I guess I’ll stick to Bash and use whatever-is-best if that’s not enough.
- 0x09 14y agoThere is actually a tool in the clang extras repository for this called clang-format. It supports three different styles ("LLVM", "Google", "Chromium") although I'm not sure where those are documented exactly. http://clang.llvm.org/docs/ClangFormat.html http://clang.llvm.org/docs/ClangFormat.html (a little outdated from HEAD)
- bla2 14y agoGoogle style is probably http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml http://google-styleguide.googlecode.com/svn/trunk/cppguide.x... , Chromium http://dev.chromium.org/developers/coding-style http://dev.chromium.org/developers/coding-style
- angersock 14y agoTwo stories regarding coding standards. ~ At my old day job (sprawling planet-eating Java), the codebase had gone through many hands over the course of ten or so years. The "age" of some code or feature could usually be determined by looking at how it was written: newest code used the Java foreach construct, older code (usually by one particular developer) used explicit for constructs, and the oldest code reimplemented (poorly) collection classes without generics. Additionally, the fist (coding style) of each person who'd worked on a section became apparent: my own code tended to have a large number of anonymous inner classes and monkey closures, as well as somewhat heavy use of interface and abstract classes. Another coder liked static factory methods a lot, as well as very shallow inheritance hierarchies (in order to make debugging simpler). The oldest code was the poster child for 90s Java: EnterpriseFactoryProxyFacadeAdaptorSingletonProviders, overly wordy code to accomplish simple tasks, etc. It was interesting to open a file or function to implement a feature or bugfix and then twitch when you realized that it was from one of the more...time-pressed...veteran... developers. By contrast, opening code in a particular style (indenting, commenting, etc.) I recognized as my own or another coworker brought relief. ~ At the same time I was working on this, I worked on a large library with some friends doing gamedev. We agreed on a coding standard, had some rather arcane arguments, and ultimately settled on something that drew heavy inspiration from Insomniac's coding guide--not exactly alike, but we at least had an opinion on nearly everything they cover. Whenever working on that code, I have a very different feeling. Despite the fact that we're all working on it at the same time, and despite the fact that we all have some remnants of our fists, the codebase still feels fairly uniform and like home. Variable naming is basically the same, choice of verbs and methods is the same, indentation is nearly the same (as are the cases where liberties are taken), commenting is consistent where it matters (fists show through in individual writing styles, but documentation for interfaces and function signatures is standardized), and overall there is a high amount of consistency. Even deeper, the amount of cleverness is roughly equivalent throughout the code--as we use C++, this cannot be undersold. We've come to a consensus on when and how to use templates, and in what ways, and when to use defines, and how we treat inheritance and interfaces and abstractions. We have house rules on how things should behave; in a language where you can overload and redefine operators, restraint is important. ~ Overall, having a common coding standard--and moreover, one that everyone has closely examined and discussed and agreed on--really helps decrease cognitive load. It gives better "faith" in your codebase, and reduces the annoyance of working on somebody else's code. It reduces the impedance mismatch of abstractions as they work together, and helps to reassure you when its three in the goddamn morning and why the christ am i getting these compiler warnings sheezus didnt anybody read through this before committing argh at least we have unit tests. It's also something a lot of people seem to dismiss as bike-shedding, and sometimes it can seem like that. It's at least worth considering, especially if you work with people you care about--coding on a team should be like a relationship, and any successful relationship involves developing a common background and shorthand for communicating.