C Beautifier & Formatter

C arrives broken in predictable ways. A patch lands with tabs against a file that used spaces. Three statements get folded onto one line to fit a diff. Someone drops sixty lines into a ticket with every statement at column zero. Paste it below and the layout is rebuilt from the brace depth counted in your source.

Style
Indent
Paste C above, or load the sample.

Pick the brace style your project already uses

Match the repository even when you dislike its choice. A reformat spread across a file buries the real diff and makes git blame useless for that region, which costs more than the layout ever gains. For a project with no history yet, K&R at 4 spaces is the safest starting point.

StyleOpening braceWhere you meet it
K&RSame line as the statementLinux kernel, BSD userland, most POSIX code
AllmanOwn line, at the statement columnWindows SDK samples, MFC, 1990s embedded C
GNUOwn line, indented half a stepglibc, coreutils, GNU Coding Standards
WhitesmithsOwn line, at the body columnInstrument and industrial firmware

The kernel case is worth knowing about. Its 8 column tabs look like an accident and are not. The kernel style document treats deep nesting as a design warning, so it makes each level expensive on purpose: run out of screen width and the function needs splitting. Set Indent to Tab with K&R braces to see what a patch has to look like before that project takes it.

What the Format button changes

Every line is rebuilt, not patched. Your source runs through a small C tokenizer first, so strings, character constants, comments and preprocessor lines are set aside before any spacing rule touches the code. That is what stops a brace inside a string literal from throwing off the indentation.

  • Indentation comes from brace depth at the width you pick. Old tabs and mixed leading whitespace are replaced outright.
  • Semicolons outside a for header break the line, so you get one statement per line.
  • Spacing follows normal C convention: around binary operators, none inside parentheses, none between a function name and its argument list, one space after if, for, while and switch.
  • Prefix and postfix operators stay glued to their operand, so *p, &x, -1 and i++ survive instead of turning into arithmetic.
  • Pointers normalize to char *p. The star binds to the declarator, not the type, and char* a, b; declares one pointer and one plain char. Right alignment keeps that visible.
  • Casts lose the gap before their value, and case labels indent under switch.
  • Trailing whitespace goes, runs of blank lines collapse to one, and goto labels outdent a level.

Output replaces your input in the same box. CtrlZ brings the original back if you want to compare.

The macro that breaks your indentation

Directives take a separate path. They sit at column 0 so #ifdef ladders stay readable inside a nested function, whitespace between # and the directive name is removed, and backslash continuation lines get one level of indent under their directive. The body of a #define is left exactly as written, spacing included, because macro text is substituted verbatim and reformatting it risks changing what the compiler sees.

One pattern defeats all of that. A macro holding half a brace pair, the classic #define BEGIN {, breaks the depth counter for every line after it. The status bar reports the mismatch rather than guessing, and indentation past that point is unreliable. If you see a brace warning on code that compiles fine, a macro is almost always the reason.

Where this stops short

  • Long lines are never wrapped. There is no column limit, so a 300 character condition stays 300 characters wide.
  • Array and struct initializers keep the line breaks you wrote. A lookup table on one line stays on one line.
  • #include lines are neither sorted nor grouped.
  • Pointer detection is a heuristic built on type keywords and the _t suffix. A typedef named Matrix in Matrix * m; reads as multiplication and gets spaced that way.
  • C++ files mostly survive, but classes, templates, namespaces and access labels are not handled. Use the C++ beautifier for those.
  • Files past roughly 2 MB are refused rather than freezing the tab.

The output will not match clang-format line for line, and it is not meant to. This page is for reading code someone pasted at you. What lands in a commit should go through the config your repository already carries.

The same job in your editor

Three tools cover almost every C codebase and all of them run offline in a pre-commit hook.

clang-format -i --style=file src/*.c indent -kr -i4 -nut reader.c astyle --style=allman --indent=spaces=4 reader.c

Commit the settings so the layout stops being a personal preference:

# .clang-format BasedOnStyle: LLVM IndentWidth: 4 UseTab: Never BreakBeforeBraces: Attach PointerAlignment: Right IndentCaseLabels: true ColumnLimit: 100

GNU indent ships with most distributions and predates clang by decades. It handles plain C fine through -kr, -gnu and -orig, though it has no idea what to do with newer attributes.

C formatting questions

Does my C source get uploaded anywhere?

No. The tokenizer and the printer are JavaScript running in this page, so nothing is posted to a server. That matters when the code belongs to an employer or a client.

The indentation broke halfway down my file. Why?

Almost always an unbalanced brace, and almost always inside a macro. Check the status bar under the editor. When it reports a brace mismatch, fix that first, because every indent decision after the bad brace is built on the wrong depth.

Which brace style should I use for a new C project?

K&R at 4 spaces if you have no other constraint. It matches what most C readers expect and it is the starting point for both LLVM and Linux kernel style. Consistency across the repository beats the specific choice.

Can I get my original code back after formatting?

Yes. The formatted output replaces the text in the editor, so Ctrl+Z steps back to what you pasted. Nothing is lost until you reload the page.

Why are case labels indented under switch?

It is the more common layout in modern C and matches IndentCaseLabels: true in clang-format. Linux kernel style puts case at the same column as switch, so kernel and driver work needs clang-format locally rather than this page.

How large a file will it take?

Up to about 2 MB. Past that the page refuses the input rather than locking up the tab, and a local run of clang-format is the better answer anyway.