My C source file format preferences

Formatting is not something developers should be spending much time on, but we spend a lot of time staring at code to see if it's right so the formatting needs to be pleasing to the eye. As such, many of the format options are subjective, with many developers' preferences coming from what they have been trained on in books and coursework as well as previously encountered codebases. Here I will attempt to justify and explain my choices.

Brace Placement Style

BreakBeforeBraces: Allman

Allman/BSD style has the advantage that the braces line up vertically so you can see that they are in matched pair. I find the offset placing that you get in K&R, One True Brace, Linux Kernel, Stroustrup, BSD KNF, Pico and Ratliff displeasing due to both the asymmetry of the brace positions for the block (sometimes called Egyptian braces) and the fact that this is inconsistent with the brace positions for other blocks, such as functions where the opening brace is always on the start of the line.

Horstmann and Pico both hoist the first statement of the block into the same line as the opening brace and hence make it difficult to remove with the common "comment out this line" editor shortcut, as well as difficult to insert #ifdef at the start of the block.

K&R, One True Brace, Linux Kernel, Stroustrup, BSD KNF and Ratliff similarly make it difficult to remove the conditional with either "comment out this line" editor shortcut, or by inserting #ifdef/#endif around it. Whereas the conditional can be removed easily in Whitesmiths and Allman styles.

//Allman style
    int c;
#ifdef HAS_GETCH
    while ((c = getch()) != EOF)
#else
    while ((c = getchar()) != EOF)
#endif
    {
        do_something(c);
    }

Whitesmiths would be my second choice because it shares most of the above aspects with Allman but it is still not quite right. The problem is that the resulting block is not formatted the same as if it were in it's own function.

//Whitesmiths style
while (x == y)
    {
    something();
    something_else();
    }

final_thing();

Therefore Allman/BSD style is the clear winner for me.

Tabs and Tab Width

UseTab: Never
IndentWidth: 4

Until the last few years, I was a tab boy in the tabs vs spaces wars. Tabs were clearly the correct selection for indenting, being a single key press instead of messing around with multiple spaces. If you want to change the look of your code, you can change the tab width in the editor and all tabs will be resized at the same time. If everyone uses tabs, you're not going to get confused with whitespace differences when differencing between code from the 2-space and the 4-space developers. (3-space developers are right out).

But code editing is not word processing. You're not going to be changing the tab width using the editor because clang-format can do it for you when you save.

Working on a shared codebase taught me that it is important to chose a whitespace format that makes the code look the same in all environments, despite the different settings users have. I also started using multiple PCs, real hardware and virtual, and different editors so even as one developer I was seeing the problems inherent in tabs. Spaces are always displayed at the same width per character at a given font size, so there is no ambiguity, and clang-format can be set to standardise the number of spaces for you. A final reason is that editors can be set up so that the tab key inserts spaces, and even to do automatic conversions between tabs and spaces.

Tab width of 4 looks right to me. STM32CubeIDE uses 2 by default which makes it harder to discern which level of indentation a line is on. If your argument is that a smaller tab width allows for more levels of indentation, then you are going to end up with more levels than is good for modular structure and hence testability and reusability.

Don't allow multi-statement lines

AllowShortBlocksOnASingleLine : false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: none
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false

It's important when stepping through code to see which lines are being executed, so you want to have each statement on it's own line. It's rare for a debugger to be able to show you which part of a line is being executed although the Visual Studio debugger is an exception to that rule.

Breakpoints are line based, so if you ever want to put a breakpoint at that statement, it needs to be on it's own line.

Contiguous line in search results

AlwaysBreakAfterReturnType: None
BreakStringLiterals: false

When you're searching for a string across files in your IDE, you're presented with the matching lines without any surrounding lines for context, so it's nice to see the whole function declaration or definition in the search summary without having to navigate to the usage. That way you can quickly see if the signatures match (number and type of parameters and return value).

Since compiler warnings and errors are line based, you shouldn't break up the line in a way that hides the meaning. If you've forgotten to match your return types, GCC shows an error on the line with the name of the function not the line with the return type, so it's best that they are the same line.

Similarly, you might be searching for string literals and it would be frustrating and misleading to not get a match because they are broken across lines.

Column Width for the modern age

ColumnLimit: 180

The popular 80 character column limit dates back to the age of CRT monitors and line printers. Barr justifies this by saying that sometimes we do code reviews on printed paper. Nearly all developers have moved on to modern online review tooling so this reason isn't currently applicable. If you want to print your code for reviews, live with line wrapping or change the column limit value temporarily. Don't crimp your daily working style on monitors for the sake of occasional printed reviews.

When modern practices of longer function and variable names are used, including qualifiers, and the // inline comment syntax, many lines are getting near or past 80 characters. I've based 180 on a readable font size (VS Code - View - Appearance - Reset Zoom) on a 1920 pixel width monitor.

Case labels are within a switch so should be indented

IndentCaseLabels: true

Since we often need to declare variables within a case, which means opening a new block, those braces should not be at the same level of indent as the switch itself. VS Code will draw vertical lines to match up braces.

Nested preprocessor directives should look nested

IndentPPDirectives: BeforeHash

Indenting is useful to help ensure the lines are within the intended #if or #ifdef section. I see no need to keep the # in column 1 at all times (AfterHash), it just makes if look like a run-time if instead of a pre-processor #if, and prevents searching for #if and #endif.

Pointer Alignment

PointerAlignment: Right

There's disagreement amongst experts in the C world on this one; whilst I can see a case for aligning left: in the line

int* p;

p is a pointer to an int so you might expect the * to be adjacent to the int, as Stroustrup puts it, the type of p is int* and he prefers that emphasis. Jens Gustedt, in Modern C (page 171) uses left alignment to modify a type in a variable declaration. But the majority of high reputation users on StackOverflow, referencing the declaration follows use pattern from K&R, prefer the right alignment, since it is *p that is an int which can be used in expressions (K&R 2nd Edition page 94 says the same thing, "it says that the expression *ip is an int").

Barr offers confusing rules which clang-format cannot meet - his rule 3.1e asks for Middle alignment in declarations but right alignment elsewhere.

In the end, the arguments I find convincing are that in C, declaration follows the same patterns as usage, and that the majority of popular and authoritative C authors and experts use right alignment: 

  • The C Programming Language, 2nd Edition, Kernighan and Richie
  • Effective C, Robert Seacord
  • Expert C Programming, Peter Van Der Linden, uses right alignment in samples although the syntax is introduced with middle alignment.
  • Dan Saks articles eg where he says the * is part of the name being declared, not the declaration specifiers (types, storage class, qualifiers).
  • Eskil Steenberg eg
  • Sean Barrett eg

Don't sort includes

SortIncludes: false

The order of lines of code usually is significant, and although the order of #includes should not usually matter, I'm sure I've encountered cases when it does which couldn't be fixed and I wouldn't want the formatter to affect the functionality. Leave my #includes alone.

Spaces within the code line

SpaceBeforeParens: ControlStatements
SpacesBeforeTrailingComments: 2
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false

Spaces after control statement keywords

To me, if(true) just looks cramped, but func () looks too spaced out.

Inline comments spaced away from code

Keeps the comments slightly away from the code for readability and separation but not so far that it runs off the pane and causes side scrolling.

A space inside the brackets looks too sparse.

Using this format in VS Code

In VS Code, the C/C++ extension already has clang-format support so you no longer need to download it from LLVM unless you want a specific (newer) version. All you have to do is drop a .clang-format file into your project and right click - Format Document or Shift-Alt-F. Recommend to auto format on save - File - Preferences - Settings - Editor - Format On Save.

Start with my clang-format file  and use the configurator to edit it while seeing the effect in the right pane on the example code, or paste in some of your own.

Alternatively, you might want to look at Peter Torelli's clang-format file which attempts to meet the Barr Embedded C Coding Standard.

Either way, as long as you are using an automatic formatter, it should save you time manually editing tabs, spaces and newlines in your files.

Thanks

Ben Falconmore for clang-format-configurator

This article was updated on January 9, 2026