요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
80 column과 긴 expression
coding-style.rst:98-117권장 line limit은 80 column이다. 긴 statement는 의미 단위로 나누고 continuation line을 parent보다 오른쪽에 배치한다. Function call과 prototype argument는 opening parenthesis 기준으로 정렬하는 방식이 일반적이다.
User-visible printk string은 grep 가능성을 깨뜨리므로 단순히 80 column을 맞추려고 literal을 여러 줄로 나누지 않는다. 80 column 초과가 오히려 정보를 더 잘 보이고 숨기지 않는다면 예외가 가능하다.
Brace와 space 배치
coding-style.rst:120-303if, switch, for, while, do 같은 statement block의 opening brace는 같은 줄 끝에 두고 closing brace는 첫 column에 둔다. Function 정의만 opening brace를 다음 줄에 둔다. 같은 statement가 이어지는 else와 do-while의 while은 closing brace 뒤 같은 줄에 둔다.
if (condition) {
do_this();
} else {
do_that();
}
int function(int x)
{
return x + 1;
}
Single simple statement에는 불필요한 brace를 생략할 수 있지만 if와 else 중 한쪽이 여러 statement라면 양쪽 모두 brace를 쓴다. Loop body에 nested control statement가 있으면 outer loop에도 brace를 둔다.
if, switch, for, while 뒤에는 space를 쓰지만 sizeof, typeof, alignof, __attribute__ 뒤에는 쓰지 않는다. Parenthesis 안쪽에 space를 넣지 않는다. Pointer 선언의 *는 variable·function name 쪽에 붙인다. Binary·ternary operator 양쪽에는 space를, unary와 ++·--, .와 -> 주변에는 space를 두지 않는다.
Local과 global 이름
coding-style.rst:306-357짧은 범위의 local loop counter는 i, 임시값은 tmp처럼 짧고 직접적인 이름을 쓸 수 있다. 반대로 global variable과 function은 count_active_users()처럼 역할을 분명히 드러내야 한다. Type 정보를 이름에 반복하는 Hungarian notation과 mixed-case 이름은 사용하지 않는다.
새 symbol과 문서에는 master/slave, blacklist/whitelist 용어를 도입하지 않고 primary/secondary, initiator/target, controller/device, allowlist/denylist 같은 문맥에 맞는 표현을 쓴다. 기존 UAPI나 hardware·protocol specification을 그대로 유지해야 하는 경우는 예외다.
Typedef를 제한적으로 사용한다
coding-style.rst:359-442Struct와 pointer를 숨기는 vps_t 같은 typedef는 실제 type과 object 성격을 감추므로 사용하지 않는다. struct virtual_container *처럼 code에서 struct임을 드러내면 type 변경과 review가 쉽다.
- Opaque object처럼 type 자체를 의도적으로 감춰야 하는 경우
- u8, u16, u32처럼 architecture와 무관하게 정확한 width를 표현하는 정수형
- Sparse가 type safety를 검사하도록 만든 명확한 new type
- C99 표준 type
- Userspace와 공유하는 type에서 예외적으로 typedef가 더 명확한 경우
새 typedef를 만들기 전에는 이름을 여러 번 쓰는 수고가 interface의 실제 type을 숨기는 비용보다 큰지 검토한다.
Function 길이와 prototype
coding-style.rst:443-525Function은 하나의 일을 수행하고 화면 한두 개 안에서 이해할 수 있을 만큼 짧게 유지한다. 깊은 nesting과 지나치게 많은 local variable은 helper로 분리할 신호다. 복잡한 function도 line 수 자체보다 개념의 응집성과 각 block의 독립성을 기준으로 나눈다.
Source file의 local function은 definition 전에 static prototype을 불필요하게 모아 두지 말고 call order에 맞춰 정의할 수 있다. Exported function prototype은 적절한 header에 두며 parameter name도 실제 역할을 설명하도록 포함한다. Prototype declaration에서 extern은 생략한다.
중앙집중식 error cleanup
coding-style.rst:526-597여러 resource를 순서대로 얻는 function은 goto label을 사용해 역순으로 해제하는 단일 exit path를 만들 수 있다. 중복 cleanup code를 줄이고 새 resource가 추가됐을 때 모든 error branch를 따로 고칠 필요가 없어진다.
Label 이름은 err1, err2보다 out_free_buffer, out_unlock처럼 실행하는 cleanup을 표현한다. Goto가 오히려 state를 숨기거나 한 번만 쓰이는 trivial cleanup이면 direct return이 더 명확할 수 있다. Errno와 acquired-state가 각 label에 도달할 때 일관되는지 확인한다.
Code가 아니라 이유를 comment한다
coding-style.rst:598-640Comment는 code를 다시 영어로 읽는 대신 왜 이 동작과 ordering이 필요한지, 어떤 hardware erratum이나 invariant를 만족하는지 설명한다. Function이 무엇을 하는지 설명해야 한다면 kernel-doc 형식으로 interface와 parameter, return을 문서화한다.
긴 block comment는 각 줄 앞에 *를 정렬하는 kernel 형식을 사용한다. Comment가 code와 어긋나지 않도록 변경 때 함께 검토한다. 명백한 statement마다 comment를 붙이면 중요한 제약이 묻힌다.
Formatting 도구, Kconfig와 data structure
coding-style.rst:641-794Formatting이 무너졌다면 scripts/Lindent, clang-format과 editor 설정을 참고할 수 있지만 자동 결과를 그대로 믿지 않고 subsystem 주변 code와 비교한다. Kconfig help는 option이 무엇을 enable하고 누가 필요한지 설명하며 indentation과 menu dependency를 기존 규칙에 맞춘다.
자주 함께 접근하는 field를 data structure에서 가까이 두고 cache-line sharing과 alignment를 고려한다. Structure는 선언 순서 자체가 ABI 또는 hardware layout이 아닌 한 의미 있는 group으로 정리하고, concurrent access와 lifetime rule을 code 가까이에 문서화한다.
Macro, enum과 control flow
coding-style.rst:795-898여러 statement macro는 do { ... } while (0)으로 감싸 if·else context에서도 하나의 statement처럼 동작하게 한다. 모든 parameter 사용을 parenthesis로 감싸고 argument를 여러 번 평가해 side effect가 반복되지 않게 한다.
Macro가 function처럼 동작할 수 있으면 static inline function이 type checking, debug와 evaluation semantics에서 낫다. Flow control을 macro 안에 숨기거나 caller local variable 이름에 의존하는 형태를 피한다. 관련 상수 집합은 의미 있는 enum을 검토한다.
Kernel message, allocation과 inline
coding-style.rst:899-1004Kernel message는 KERN 계열 또는 pr_*·dev_* level을 상황에 맞게 선택한다. Device 관련 message는 device identity가 자동으로 붙는 dev_err, dev_warn, dev_info를 사용한다. 같은 오류가 반복되는 경로에는 rate limiting을 고려하고 정상 동작을 error level로 출력하지 않는다.
Memory allocation은 sizeof(type)보다 sizeof(*ptr)를 사용해 declaration과 allocation type이 어긋나지 않게 한다. Array와 trailing object는 kmalloc_array, struct_size 같은 overflow-aware helper를 사용하며 cast로 kmalloc return을 가리지 않는다.
inline은 compiler에게 강제 명령이 아니며 code size와 instruction cache에 악영향을 줄 수 있다. 매우 작거나 compile-time constant 최적화가 중요한 function 외에는 compiler 판단에 맡기고 단순히 call overhead를 두려워해 남용하지 않는다.
Return value, bool과 기존 helper
coding-style.rst:1005-1092Function 이름은 return convention을 예상할 수 있게 한다. Predicate는 true·false를 반환하고 action function은 성공 0과 negative errno를 쓰는 관례를 따른다. Pointer-returning function은 실패에 NULL 또는 ERR_PTR 중 무엇을 쓰는지 interface 문맥에 맞춘다.
실제 boolean state에는 bool과 true·false를 쓰되 bitfield 크기나 hardware register에 bool을 억지로 사용하지 않는다. ARRAY_SIZE, FIELD_GET, min_t와 container_of처럼 검증된 kernel macro가 이미 있으면 동일 기능을 직접 다시 구현하지 않는다.
Inline assembly와 conditional compilation
coding-style.rst:1093-1207Editor modeline처럼 개인 도구 설정을 source에 넣지 않는다. Inline assembly는 C로 표현할 수 없고 architecture primitive로 격리할 수 있을 때만 사용하며 constraint, clobber와 memory effect를 정확히 선언한다.
C source 안의 #ifdef를 넓게 퍼뜨리기보다 header의 stub helper와 IS_ENABLED(CONFIG_...)를 사용해 type checking을 유지한다. Configuration에 따라 function 전체가 필요 없다면 Makefile에서 object build를 제어한다. Conditional branch마다 독립적으로 build되는지 확인한다.
Kernel을 의도적으로 crash시키지 않는다
coding-style.rst:1208-1269복구 가능한 error에 panic을 사용하지 않는다. BUG와 BUG_ON은 lock과 state를 정리하지 못한 채 execution을 중단하므로 WARN 계열과 정상 error path로 바꾼다.
반복 가능한 invariant violation에는 WARN_ON_ONCE를 우선 검토해 log flood를 막는다. WARN은 도달해서는 안 되는 kernel bug에만 쓰며 잘못된 userspace input이나 예상 가능한 hardware failure에 사용하지 않는다. panic_on_warn 설정 사용자를 이유로 필요한 WARN을 피하지는 않는다.
Compile-time에 확인할 수 있는 invariant는 runtime BUG가 아니라 BUILD_BUG_ON이나 static assertion으로 검증한다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. _codingstyle:
Linux kernel coding style
=========================
This is a short document describing the preferred coding style for the
linux kernel. Coding style is very personal, and I won't **force** my
views on anybody, but this is what goes for anything that I have to be
able to maintain, and I'd prefer it for most other things too. Please
at least consider the points made here.
First off, I'd suggest printing out a copy of the GNU coding standards,
and NOT read it. Burn them, it's a great symbolic gesture.
Anyway, here goes:
1) Indentation
--------------
Tabs are 8 characters, and thus indentations are also 8 characters.
There are heretic movements that try to make indentations 4 (or even 2!)
characters deep, and that is akin to trying to define the value of PI to
be 3.
Rationale: The whole idea behind indentation is to clearly define where
a block of control starts and ends. Especially when you've been looking
at your screen for 20 straight hours, you'll find it a lot easier to see
how the indentation works if you have large indentations.
Now, some people will claim that having 8-character indentations makes
the code move too far to the right, and makes it hard to read on a
80-character terminal screen. The answer to that is that if you need
more than 3 levels of indentation, you're screwed anyway, and should fix
your program.
In short, 8-char indents make things easier to read, and have the added
benefit of warning you when you're nesting your functions too deep.
Heed that warning.
The preferred way to ease multiple indentation levels in a switch statement is
to align the ``switch`` and its subordinate ``case`` labels in the same column
instead of ``double-indenting`` the ``case`` labels. E.g.:
.. code-block:: c
switch (suffix) {
case 'G':
case 'g':
mem <<= 30;
break;
case 'M':
case 'm':
mem <<= 20;
break;
case 'K':
case 'k':
mem <<= 10;
fallthrough;
default:
break;
}
Don't put multiple statements on a single line unless you have
something to hide:
.. code-block:: c
if (condition) do_this;
do_something_everytime;
Don't use commas to avoid using braces:
.. code-block:: c
if (condition)
do_this(), do_that();
Always uses braces for multiple statements:
.. code-block:: c
if (condition) {
do_this();
do_that();
}
Don't put multiple assignments on a single line either. Kernel coding style
is super simple. Avoid tricky expressions.
Outside of comments, documentation and except in Kconfig, spaces are never
used for indentation, and the above example is deliberately broken.
Get a decent editor and don't leave whitespace at the end of lines.
2) Breaking long lines and strings
----------------------------------
Coding style is all about readability and maintainability using commonly
available tools.
The preferred limit on the length of a single line is 80 columns.
Statements longer than 80 columns should be broken into sensible chunks,
unless exceeding 80 columns significantly increases readability and does
not hide information.
Descendants are always substantially shorter than the parent and
are placed substantially to the right. A very commonly used style
is to align descendants to a function open parenthesis.
These same rules are applied to function headers with a long argument list.
However, never break user-visible strings such as printk messages because
that breaks the ability to grep for them.
3) Placing Braces and Spaces
----------------------------
The other issue that always comes up in C styling is the placement of
braces. Unlike the indent size, there are few technical reasons to
choose one placement strategy over the other, but the preferred way, as
shown to us by the prophets Kernighan and Ritchie, is to put the opening
brace last on the line, and put the closing brace first, thusly:
.. code-block:: c
if (x is true) {
we do y
}
This applies to all non-function statement blocks (if, switch, for,
while, do). E.g.:
.. code-block:: c
switch (action) {
case KOBJ_ADD:
return "add";
case KOBJ_REMOVE:
return "remove";
case KOBJ_CHANGE:
return "change";
default:
return NULL;
}
However, there is one special case, namely functions: they have the
opening brace at the beginning of the next line, thus:
.. code-block:: c
int function(int x)
{
body of function
}
Heretic people all over the world have claimed that this inconsistency
is ... well ... inconsistent, but all right-thinking people know that
(a) K&R are **right** and (b) K&R are right. Besides, functions are
special anyway (you can't nest them in C).
Note that the closing brace is empty on a line of its own, **except** in
the cases where it is followed by a continuation of the same statement,
ie a ``while`` in a do-statement or an ``else`` in an if-statement, like
this:
.. code-block:: c
do {
body of do-loop
} while (condition);
and
.. code-block:: c
if (x == y) {
..
} else if (x > y) {
...
} else {
....
}
Rationale: K&R.
Also, note that this brace-placement also minimizes the number of empty
(or almost empty) lines, without any loss of readability. Thus, as the
supply of new-lines on your screen is not a renewable resource (think
25-line terminal screens here), you have more empty lines to put
comments on.
Do not unnecessarily use braces where a single statement will do.
.. code-block:: c
if (condition)
action();
and
.. code-block:: c
if (condition)
do_this();
else
do_that();
This does not apply if only one branch of a conditional statement is a single
statement; in the latter case use braces in both branches:
.. code-block:: c
if (condition) {
do_this();
do_that();
} else {
otherwise();
}
Also, use braces when a loop contains more than a single simple statement:
.. code-block:: c
while (condition) {
if (test)
do_something();
}
3.1) Spaces
***********
Linux kernel style for use of spaces depends (mostly) on
function-versus-keyword usage. Use a space after (most) keywords. The
notable exceptions are sizeof, typeof, alignof, and __attribute__, which look
somewhat like functions (and are usually used with parentheses in Linux,
although they are not required in the language, as in: ``sizeof info`` after
``struct fileinfo info;`` is declared).
So use a space after these keywords::
if, switch, case, for, do, while
but not with sizeof, typeof, alignof, or __attribute__. E.g.,
.. code-block:: c
s = sizeof(struct file);
Do not add spaces around (inside) parenthesized expressions. This example is
**bad**:
.. code-block:: c
s = sizeof( struct file );
When declaring pointer data or a function that returns a pointer type, the
preferred use of ``*`` is adjacent to the data name or function name and not
adjacent to the type name. Examples:
.. code-block:: c
char *linux_banner;
unsigned long long memparse(char *ptr, char **retptr);
char *match_strdup(substring_t *s);
Use one space around (on each side of) most binary and ternary operators,
such as any of these::
= + - < > * / % | & ^ <= >= == != ? :
but no space after unary operators::
& * + - ~ ! sizeof typeof alignof __attribute__ defined
no space before the postfix increment & decrement unary operators::
++ --
no space after the prefix increment & decrement unary operators::
++ --
and no space around the ``.`` and ``->`` structure member operators.
Do not leave trailing whitespace at the ends of lines. Some editors with
``smart`` indentation will insert whitespace at the beginning of new lines as
appropriate, so you can start typing the next line of code right away.
However, some such editors do not remove the whitespace if you end up not
putting a line of code there, such as if you leave a blank line. As a result,
you end up with lines containing trailing whitespace.
Git will warn you about patches that introduce trailing whitespace, and can
optionally strip the trailing whitespace for you; however, if applying a series
of patches, this may make later patches in the series fail by changing their
context lines.
4) Naming
---------
C is a Spartan language, and your naming conventions should follow suit.
Unlike Modula-2 and Pascal programmers, C programmers do not use cute
names like ThisVariableIsATemporaryCounter. A C programmer would call that
variable ``tmp``, which is much easier to write, and not the least more
difficult to understand.
HOWEVER, while mixed-case names are frowned upon, descriptive names for
global variables are a must. To call a global function ``foo`` is a
shooting offense.
GLOBAL variables (to be used only if you **really** need them) need to
have descriptive names, as do global functions. If you have a function
that counts the number of active users, you should call that
``count_active_users()`` or similar, you should **not** call it ``cntusr()``.
Encoding the type of a function into the name (so-called Hungarian
notation) is asinine - the compiler knows the types anyway and can check
those, and it only confuses the programmer.
LOCAL variable names should be short, and to the point. If you have
some random integer loop counter, it should probably be called ``i``.
Calling it ``loop_counter`` is non-productive, if there is no chance of it
being mis-understood. Similarly, ``tmp`` can be just about any type of
variable that is used to hold a temporary value.
If you are afraid to mix up your local variable names, you have another
problem, which is called the function-growth-hormone-imbalance syndrome.
See chapter 6 (Functions).
For symbol names and documentation, avoid introducing new usage of
'master / slave' (or 'slave' independent of 'master') and 'blacklist /
whitelist'.
Recommended replacements for 'master / slave' are:
'{primary,main} / {secondary,replica,subordinate}'
'{initiator,requester} / {target,responder}'
'{controller,host} / {device,worker,proxy}'
'leader / follower'
'director / performer'
Recommended replacements for 'blacklist/whitelist' are:
'denylist / allowlist'
'blocklist / passlist'
Exceptions for introducing new usage is to maintain a userspace ABI/API,
or when updating code for an existing (as of 2020) hardware or protocol
specification that mandates those terms. For new specifications
translate specification usage of the terminology to the kernel coding
standard where possible.
5) Typedefs
-----------
Please don't use things like ``vps_t``.
It's a **mistake** to use typedef for structures and pointers. When you see a
.. code-block:: c
vps_t a;
in the source, what does it mean?
In contrast, if it says
.. code-block:: c
struct virtual_container *a;
you can actually tell what ``a`` is.
Lots of people think that typedefs ``help readability``. Not so. They are
useful only for:
(a) totally opaque objects (where the typedef is actively used to **hide**
what the object is).
Example: ``pte_t`` etc. opaque objects that you can only access using
the proper accessor functions.
.. note::
Opaqueness and ``accessor functions`` are not good in themselves.
The reason we have them for things like pte_t etc. is that there
really is absolutely **zero** portably accessible information there.
(b) Clear integer types, where the abstraction **helps** avoid confusion
whether it is ``int`` or ``long``.
u8/u16/u32 are perfectly fine typedefs, although they fit into
category (d) better than here.
.. note::
Again - there needs to be a **reason** for this. If something is
``unsigned long``, then there's no reason to do
typedef unsigned long myflags_t;
but if there is a clear reason for why it under certain circumstances
might be an ``unsigned int`` and under other configurations might be
``unsigned long``, then by all means go ahead and use a typedef.
(c) when you use sparse to literally create a **new** type for
type-checking.
(d) New types which are identical to standard C99 types, in certain
exceptional circumstances.
Although it would only take a short amount of time for the eyes and
brain to become accustomed to the standard types like ``uint32_t``,
some people object to their use anyway.
Therefore, the Linux-specific ``u8/u16/u32/u64`` types and their
signed equivalents which are identical to standard types are
permitted -- although they are not mandatory in new code of your
own.
When editing existing code which already uses one or the other set
of types, you should conform to the existing choices in that code.
(e) Types safe for use in userspace.
In certain structures which are visible to userspace, we cannot
require C99 types and cannot use the ``u32`` form above. Thus, we
use __u32 and similar types in all structures which are shared
with userspace.
Maybe there are other cases too, but the rule should basically be to NEVER
EVER use a typedef unless you can clearly match one of those rules.
In general, a pointer, or a struct that has elements that can reasonably
be directly accessed should **never** be a typedef.
6) Functions
------------
Functions should be short and sweet, and do just one thing. They should
fit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24,
as we all know), and do one thing and do that well.
The maximum length of a function is inversely proportional to the
complexity and indentation level of that function. So, if you have a
conceptually simple function that is just one long (but simple)
case-statement, where you have to do lots of small things for a lot of
different cases, it's OK to have a longer function.
However, if you have a complex function, and you suspect that a
less-than-gifted first-year high-school student might not even
understand what the function is all about, you should adhere to the
maximum limits all the more closely. Use helper functions with
descriptive names (you can ask the compiler to in-line them if you think
it's performance-critical, and it will probably do a better job of it
than you would have done).
Another measure of the function is the number of local variables. They
shouldn't exceed 5-10, or you're doing something wrong. Re-think the
function, and split it into smaller pieces. A human brain can
generally easily keep track of about 7 different things, anything more
and it gets confused. You know you're brilliant, but maybe you'd like
to understand what you did 2 weeks from now.
In source files, separate functions with one blank line. If the function is
exported, the **EXPORT** macro for it should follow immediately after the
closing function brace line. E.g.:
.. code-block:: c
int system_is_up(void)
{
return system_state == SYSTEM_RUNNING;
}
EXPORT_SYMBOL(system_is_up);
6.1) Function prototypes
************************
In function prototypes, include parameter names with their data types.
Although this is not required by the C language, it is preferred in Linux
because it is a simple way to add valuable information for the reader.
Do not use the ``extern`` keyword with function declarations as this makes
lines longer and isn't strictly necessary.
When writing function prototypes, please keep the `order of elements regular
<https://lore.kernel.org/mm-commits/CAHk-=wiOCLRny5aifWNhr621kYrJwhfURsa0vFPeUEm8mF0ufg@mail.gmail.com/>`_.
For example, using this function declaration example::
__init void * __must_check action(enum magic value, size_t size, u8 count,
char *fmt, ...) __printf(4, 5) __malloc;
The preferred order of elements for a function prototype is:
- storage class (below, ``static __always_inline``, noting that ``__always_inline``
is technically an attribute but is treated like ``inline``)
- storage class attributes (here, ``__init`` -- i.e. section declarations, but also
things like ``__cold``)
- return type (here, ``void *``)
- return type attributes (here, ``__must_check``)
- function name (here, ``action``)
- function parameters (here, ``(enum magic value, size_t size, u8 count, char *fmt, ...)``,
noting that parameter names should always be included)
- function parameter attributes (here, ``__printf(4, 5)``)
- function behavior attributes (here, ``__malloc``)
Note that for a function **definition** (i.e. the actual function body),
the compiler does not allow function parameter attributes after the
function parameters. In these cases, they should go after the storage
class attributes (e.g. note the changed position of ``__printf(4, 5)``
below, compared to the **declaration** example above)::
static __always_inline __init __printf(4, 5) void * __must_check action(enum magic value,
size_t size, u8 count, char *fmt, ...) __malloc
{
...
}
7) Centralized exiting of functions
-----------------------------------
Albeit deprecated by some people, the equivalent of the goto statement is
used frequently by compilers in form of the unconditional jump instruction.
The goto statement comes in handy when a function exits from multiple
locations and some common work such as cleanup has to be done. If there is no
cleanup needed then just return directly.
Choose label names which say what the goto does or why the goto exists. An
example of a good name could be ``out_free_buffer:`` if the goto frees ``buffer``.
Avoid using GW-BASIC names like ``err1:`` and ``err2:``, as you would have to
renumber them if you ever add or remove exit paths, and they make correctness
difficult to verify anyway.
The rationale for using gotos is:
- unconditional statements are easier to understand and follow
- nesting is reduced
- errors by not updating individual exit points when making
modifications are prevented
- saves the compiler work to optimize redundant code away ;)
.. code-block:: c
int fun(int a)
{
int result = 0;
char *buffer;
buffer = kmalloc(SIZE, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
if (condition1) {
while (loop1) {
...
}
result = 1;
goto out_free_buffer;
}
...
out_free_buffer:
kfree(buffer);
return result;
}
A common type of bug to be aware of is ``one err bugs`` which look like this:
.. code-block:: c
err:
kfree(foo->bar);
kfree(foo);
return ret;
The bug in this code is that on some exit paths ``foo`` is NULL. Normally the
fix for this is to split it up into two error labels ``err_free_bar:`` and
``err_free_foo:``:
.. code-block:: c
err_free_bar:
kfree(foo->bar);
err_free_foo:
kfree(foo);
return ret;
Ideally you should simulate errors to test all exit paths.
8) Commenting
-------------
Comments are good, but there is also a danger of over-commenting. NEVER
try to explain HOW your code works in a comment: it's much better to
write the code so that the **working** is obvious, and it's a waste of
time to explain badly written code.
Generally, you want your comments to tell WHAT your code does, not HOW.
Also, try to avoid putting comments inside a function body: if the
function is so complex that you need to separately comment parts of it,
you should probably go back to chapter 6 for a while. You can make
small comments to note or warn about something particularly clever (or
ugly), but try to avoid excess. Instead, put the comments at the head
of the function, telling people what it does, and possibly WHY it does
it.
When commenting the kernel API functions, please use the kernel-doc format.
See the files at :ref:`Documentation/doc-guide/ <doc_guide>` and
``scripts/kernel-doc`` for details. Note that the danger of over-commenting
applies to kernel-doc comments all the same. Do not add boilerplate
kernel-doc which simply reiterates what's obvious from the signature
of the function.
The preferred style for long (multi-line) comments is:
.. code-block:: c
/*
* This is the preferred style for multi-line
* comments in the Linux kernel source code.
* Please use it consistently.
*
* Description: A column of asterisks on the left side,
* with beginning and ending almost-blank lines.
*/
It's also important to comment data, whether they are basic types or derived
types. To this end, use just one data declaration per line (no commas for
multiple data declarations). This leaves you room for a small comment on each
item, explaining its use.
9) You've made a mess of it
---------------------------
That's OK, we all do. You've probably been told by your long-time Unix
user helper that ``GNU emacs`` automatically formats the C sources for
you, and you've noticed that yes, it does do that, but the defaults it
uses are less than desirable (in fact, they are worse than random
typing - an infinite number of monkeys typing into GNU emacs would never
make a good program).
So, you can either get rid of GNU emacs, or change it to use saner
values. To do the latter, you can stick the following in your .emacs file:
.. code-block:: elisp
(defun c-lineup-arglist-tabs-only (ignored)
"Line up argument lists by tabs, not spaces"
(let* ((anchor (c-langelem-pos c-syntactic-element))
(column (c-langelem-2nd-pos c-syntactic-element))
(offset (- (1+ column) anchor))
(steps (floor offset c-basic-offset)))
(* (max steps 1)
c-basic-offset)))
(dir-locals-set-class-variables
'linux-kernel
'((c-mode . (
(c-basic-offset . 8)
(c-label-minimum-indentation . 0)
(c-offsets-alist . (
(arglist-close . c-lineup-arglist-tabs-only)
(arglist-cont-nonempty .
(c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only))
(arglist-intro . +)
(brace-list-intro . +)
(c . c-lineup-C-comments)
(case-label . 0)
(comment-intro . c-lineup-comment)
(cpp-define-intro . +)
(cpp-macro . -1000)
(cpp-macro-cont . +)
(defun-block-intro . +)
(else-clause . 0)
(func-decl-cont . +)
(inclass . +)
(inher-cont . c-lineup-multi-inher)
(knr-argdecl-intro . 0)
(label . -1000)
(statement . 0)
(statement-block-intro . +)
(statement-case-intro . +)
(statement-cont . +)
(substatement . +)
))
(indent-tabs-mode . t)
(show-trailing-whitespace . t)
))))
(dir-locals-set-directory-class
(expand-file-name "~/src/linux-trees")
'linux-kernel)
This will make emacs go better with the kernel coding style for C
files below ``~/src/linux-trees``.
But even if you fail in getting emacs to do sane formatting, not
everything is lost: use ``indent``.
Now, again, GNU indent has the same brain-dead settings that GNU emacs
has, which is why you need to give it a few command line options.
However, that's not too bad, because even the makers of GNU indent
recognize the authority of K&R (the GNU people aren't evil, they are
just severely misguided in this matter), so you just give indent the
options ``-kr -i8`` (stands for ``K&R, 8 character indents``), or use
``scripts/Lindent``, which indents in the latest style.
``indent`` has a lot of options, and especially when it comes to comment
re-formatting you may want to take a look at the man page. But
remember: ``indent`` is not a fix for bad programming.
Note that you can also use the ``clang-format`` tool to help you with
these rules, to quickly re-format parts of your code automatically,
and to review full files in order to spot coding style mistakes,
typos and possible improvements. It is also handy for sorting ``#includes``,
for aligning variables/macros, for reflowing text and other similar tasks.
See the file :ref:`Documentation/dev-tools/clang-format.rst <clangformat>`
for more details.
Some basic editor settings, such as indentation and line endings, will be
set automatically if you are using an editor that is compatible with
EditorConfig. See the official EditorConfig website for more information:
https://editorconfig.org/
10) Kconfig configuration files
-------------------------------
For all of the Kconfig* configuration files throughout the source tree,
the indentation is somewhat different. Lines under a ``config`` definition
are indented with one tab, while help text is indented an additional two
spaces. Example::
config AUDIT
bool "Auditing support"
depends on NET
help
Enable auditing infrastructure that can be used with another
kernel subsystem, such as SELinux (which requires this for
logging of avc messages output). Does not do system-call
auditing without CONFIG_AUDITSYSCALL.
Seriously dangerous features (such as write support for certain
filesystems) should advertise this prominently in their prompt string::
config ADFS_FS_RW
bool "ADFS write support (DANGEROUS)"
depends on ADFS_FS
...
For full documentation on the configuration files, see the file
Documentation/kbuild/kconfig-language.rst.
11) Data structures
-------------------
Data structures that have visibility outside the single-threaded
environment they are created and destroyed in should always have
reference counts. In the kernel, garbage collection doesn't exist (and
outside the kernel garbage collection is slow and inefficient), which
means that you absolutely **have** to reference count all your uses.
Reference counting means that you can avoid locking, and allows multiple
users to have access to the data structure in parallel - and not having
to worry about the structure suddenly going away from under them just
because they slept or did something else for a while.
Note that locking is **not** a replacement for reference counting.
Locking is used to keep data structures coherent, while reference
counting is a memory management technique. Usually both are needed, and
they are not to be confused with each other.
Many data structures can indeed have two levels of reference counting,
when there are users of different ``classes``. The subclass count counts
the number of subclass users, and decrements the global count just once
when the subclass count goes to zero.
Examples of this kind of ``multi-level-reference-counting`` can be found in
memory management (``struct mm_struct``: mm_users and mm_count), and in
filesystem code (``struct super_block``: s_count and s_active).
Remember: if another thread can find your data structure, and you don't
have a reference count on it, you almost certainly have a bug.
12) Macros, Enums and RTL
-------------------------
Names of macros defining constants and labels in enums are capitalized.
.. code-block:: c
#define CONSTANT 0x12345
Enums are preferred when defining several related constants.
CAPITALIZED macro names are appreciated but macros resembling functions
may be named in lower case.
Generally, inline functions are preferable to macros resembling functions.
Macros with multiple statements should be enclosed in a do - while block:
.. code-block:: c
#define macrofun(a, b, c) \
do { \
if (a == 5) \
do_this(b, c); \
} while (0)
Function-like macros with unused parameters should be replaced by static
inline functions to avoid the issue of unused variables:
.. code-block:: c
static inline void fun(struct foo *foo)
{
}
Due to historical practices, many files still employ the "cast to (void)"
approach to evaluate parameters. However, this method is not advisable.
Inline functions address the issue of "expression with side effects
evaluated more than once", circumvent unused-variable problems, and
are generally better documented than macros for some reason.
.. code-block:: c
/*
* Avoid doing this whenever possible and instead opt for static
* inline functions
*/
#define macrofun(foo) do { (void) (foo); } while (0)
Things to avoid when using macros:
1) macros that affect control flow:
.. code-block:: c
#define FOO(x) \
do { \
if (blah(x) < 0) \
return -EBUGGERED; \
} while (0)
is a **very** bad idea. It looks like a function call but exits the ``calling``
function; don't break the internal parsers of those who will read the code.
2) macros that depend on having a local variable with a magic name:
.. code-block:: c
#define FOO(val) bar(index, val)
might look like a good thing, but it's confusing as hell when one reads the
code and it's prone to breakage from seemingly innocent changes.
3) macros with arguments that are used as l-values: FOO(x) = y; will
bite you if somebody e.g. turns FOO into an inline function.
4) forgetting about precedence: macros defining constants using expressions
must enclose the expression in parentheses. Beware of similar issues with
macros using parameters.
.. code-block:: c
#define CONSTANT 0x4000
#define CONSTEXP (CONSTANT | 3)
5) namespace collisions when defining local variables in macros resembling
functions:
.. code-block:: c
#define FOO(x) \
({ \
typeof(x) ret; \
ret = calc_ret(x); \
(ret); \
})
ret is a common name for a local variable - __foo_ret is less likely
to collide with an existing variable.
The cpp manual deals with macros exhaustively. The gcc internals manual also
covers RTL which is used frequently with assembly language in the kernel.
13) Printing kernel messages
----------------------------
Kernel developers like to be seen as literate. Do mind the spelling
of kernel messages to make a good impression. Do not use incorrect
contractions like ``dont``; use ``do not`` or ``don't`` instead. Make the
messages concise, clear, and unambiguous.
Kernel messages do not have to be terminated with a period.
Printing numbers in parentheses (%d) adds no value and should be avoided.
There are a number of driver model diagnostic macros in <linux/dev_printk.h>
which you should use to make sure messages are matched to the right device
and driver, and are tagged with the right level: dev_err(), dev_warn(),
dev_info(), and so forth. For messages that aren't associated with a
particular device, <linux/printk.h> defines pr_notice(), pr_info(),
pr_warn(), pr_err(), etc. When drivers are working properly they are quiet,
so prefer to use dev_dbg/pr_debug unless something is wrong.
Coming up with good debugging messages can be quite a challenge; and once
you have them, they can be a huge help for remote troubleshooting. However
debug message printing is handled differently than printing other non-debug
messages. While the other pr_XXX() functions print unconditionally,
pr_debug() does not; it is compiled out by default, unless either DEBUG is
defined or CONFIG_DYNAMIC_DEBUG is set. That is true for dev_dbg() also,
and a related convention uses VERBOSE_DEBUG to add dev_vdbg() messages to
the ones already enabled by DEBUG.
Many subsystems have Kconfig debug options to turn on -DDEBUG in the
corresponding Makefile; in other cases specific files #define DEBUG. And
when a debug message should be unconditionally printed, such as if it is
already inside a debug-related #ifdef section, printk(KERN_DEBUG ...) can be
used.
14) Allocating memory
---------------------
The kernel provides the following general purpose memory allocators:
kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc(), and
vzalloc(). Please refer to the API documentation for further information
about them. :ref:`Documentation/core-api/memory-allocation.rst
<memory_allocation>`
The preferred form for passing a size of a struct is the following:
.. code-block:: c
p = kmalloc(sizeof(*p), ...);
The alternative form where struct name is spelled out hurts readability and
introduces an opportunity for a bug when the pointer variable type is changed
but the corresponding sizeof that is passed to a memory allocator is not.
Casting the return value which is a void pointer is redundant. The conversion
from void pointer to any other pointer type is guaranteed by the C programming
language.
The preferred form for allocating an array is the following:
.. code-block:: c
p = kmalloc_array(n, sizeof(...), ...);
The preferred form for allocating a zeroed array is the following:
.. code-block:: c
p = kcalloc(n, sizeof(...), ...);
Both forms check for overflow on the allocation size n * sizeof(...),
and return NULL if that occurred.
These generic allocation functions all emit a stack dump on failure when used
without __GFP_NOWARN so there is no use in emitting an additional failure
message when NULL is returned.
15) The inline disease
----------------------
There appears to be a common misperception that gcc has a magic "make me
faster" speedup option called ``inline``. While the use of inlines can be
appropriate (for example as a means of replacing macros, see Chapter 12), it
very often is not. Abundant use of the inline keyword leads to a much bigger
kernel, which in turn slows the system as a whole down, due to a bigger
icache footprint for the CPU and simply because there is less memory
available for the pagecache. Just think about it; a pagecache miss causes a
disk seek, which easily takes 5 milliseconds. There are a LOT of cpu cycles
that can go into these 5 milliseconds.
A reasonable rule of thumb is to not put inline at functions that have more
than 3 lines of code in them. An exception to this rule are the cases where
a parameter is known to be a compile time constant, and as a result of this
constantness you *know* the compiler will be able to optimize most of your
function away at compile time. For a good example of this later case, see
the kmalloc() inline function.
Often people argue that adding inline to functions that are static and used
only once is always a win since there is no space tradeoff. While this is
technically correct, gcc is capable of inlining these automatically without
help, and the maintenance issue of removing the inline when a second user
appears outweighs the potential value of the hint that tells gcc to do
something it would have done anyway.
16) Function return values and names
------------------------------------
Functions can return values of many different kinds, and one of the
most common is a value indicating whether the function succeeded or
failed. Such a value can be represented as an error-code integer
(-Exxx = failure, 0 = success) or a ``succeeded`` boolean (0 = failure,
non-zero = success).
Mixing up these two sorts of representations is a fertile source of
difficult-to-find bugs. If the C language included a strong distinction
between integers and booleans then the compiler would find these mistakes
for us... but it doesn't. To help prevent such bugs, always follow this
convention::
If the name of a function is an action or an imperative command,
the function should return an error-code integer. If the name
is a predicate, the function should return a "succeeded" boolean.
For example, ``add work`` is a command, and the add_work() function returns 0
for success or -EBUSY for failure. In the same way, ``PCI device present`` is
a predicate, and the pci_dev_present() function returns 1 if it succeeds in
finding a matching device or 0 if it doesn't.
All EXPORTed functions must respect this convention, and so should all
public functions. Private (static) functions need not, but it is
recommended that they do.
Functions whose return value is the actual result of a computation, rather
than an indication of whether the computation succeeded, are not subject to
this rule. Generally they indicate failure by returning some out-of-range
result. Typical examples would be functions that return pointers; they use
NULL or the ERR_PTR mechanism to report failure.
17) Using bool
--------------
The Linux kernel bool type is an alias for the C99 _Bool type. bool values can
only evaluate to 0 or 1, and implicit or explicit conversion to bool
automatically converts the value to true or false. When using bool types the
!! construction is not needed, which eliminates a class of bugs.
When working with bool values the true and false definitions should be used
instead of 1 and 0.
bool function return types and stack variables are always fine to use whenever
appropriate. Use of bool is encouraged to improve readability and is often a
better option than 'int' for storing boolean values.
Do not use bool if cache line layout or size of the value matters, as its size
and alignment varies based on the compiled architecture. Structures that are
optimized for alignment and size should not use bool.
If a structure has many true/false values, consider consolidating them into a
bitfield with 1 bit members, or using an appropriate fixed width type, such as
u8.
Similarly for function arguments, many true/false values can be consolidated
into a single bitwise 'flags' argument and 'flags' can often be a more
readable alternative if the call-sites have naked true/false constants.
Otherwise limited use of bool in structures and arguments can improve
readability.
18) Don't re-invent the kernel macros
-------------------------------------
The header file include/linux/kernel.h contains a number of macros that
you should use, rather than explicitly coding some variant of them yourself.
For example, if you need to calculate the length of an array, take advantage
of the macro
.. code-block:: c
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
Similarly, if you need to calculate the size of some structure member, use
.. code-block:: c
#define sizeof_field(t, f) (sizeof(((t*)0)->f))
There are also min() and max() macros that do strict type checking if you
need them. Feel free to peruse that header file to see what else is already
defined that you shouldn't reproduce in your code.
19) Editor modelines and other cruft
------------------------------------
Some editors can interpret configuration information embedded in source files,
indicated with special markers. For example, emacs interprets lines marked
like this:
.. code-block:: c
-*- mode: c -*-
Or like this:
.. code-block:: c
/*
Local Variables:
compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"
End:
*/
Vim interprets markers that look like this:
.. code-block:: c
/* vim:set sw=8 noet */
Do not include any of these in source files. People have their own personal
editor configurations, and your source files should not override them. This
includes markers for indentation and mode configuration. People may use their
own custom mode, or may have some other magic method for making indentation
work correctly.
20) Inline assembly
-------------------
In architecture-specific code, you may need to use inline assembly to interface
with CPU or platform functionality. Don't hesitate to do so when necessary.
However, don't use inline assembly gratuitously when C can do the job. You can
and should poke hardware from C when possible.
Consider writing simple helper functions that wrap common bits of inline
assembly, rather than repeatedly writing them with slight variations. Remember
that inline assembly can use C parameters.
Large, non-trivial assembly functions should go in .S files, with corresponding
C prototypes defined in C header files. The C prototypes for assembly
functions should use ``asmlinkage``.
You may need to mark your asm statement as volatile, to prevent GCC from
removing it if GCC doesn't notice any side effects. You don't always need to
do so, though, and doing so unnecessarily can limit optimization.
When writing a single inline assembly statement containing multiple
instructions, put each instruction on a separate line in a separate quoted
string, and end each string except the last with ``\n\t`` to properly indent
the next instruction in the assembly output:
.. code-block:: c
asm ("magic %reg1, #42\n\t"
"more_magic %reg2, %reg3"
: /* outputs */ : /* inputs */ : /* clobbers */);
21) Conditional Compilation
---------------------------
Wherever possible, don't use preprocessor conditionals (#if, #ifdef) in .c
files; doing so makes code harder to read and logic harder to follow. Instead,
use such conditionals in a header file defining functions for use in those .c
files, providing no-op stub versions in the #else case, and then call those
functions unconditionally from .c files. The compiler will avoid generating
any code for the stub calls, producing identical results, but the logic will
remain easy to follow.
Prefer to compile out entire functions, rather than portions of functions or
portions of expressions. Rather than putting an ifdef in an expression, factor
out part or all of the expression into a separate helper function and apply the
conditional to that function.
If you have a function or variable which may potentially go unused in a
particular configuration, and the compiler would warn about its definition
going unused, mark the definition as __maybe_unused rather than wrapping it in
a preprocessor conditional. (However, if a function or variable *always* goes
unused, delete it.)
Within code, where possible, use the IS_ENABLED macro to convert a Kconfig
symbol into a C boolean expression, and use it in a normal C conditional:
.. code-block:: c
if (IS_ENABLED(CONFIG_SOMETHING)) {
...
}
The compiler will constant-fold the conditional away, and include or exclude
the block of code just as with an #ifdef, so this will not add any runtime
overhead. However, this approach still allows the C compiler to see the code
inside the block, and check it for correctness (syntax, types, symbol
references, etc). Thus, you still have to use an #ifdef if the code inside the
block references symbols that will not exist if the condition is not met.
At the end of any non-trivial #if or #ifdef block (more than a few lines),
place a comment after the #endif on the same line, noting the conditional
expression used. For instance:
.. code-block:: c
#ifdef CONFIG_SOMETHING
...
#endif /* CONFIG_SOMETHING */
22) Do not crash the kernel
---------------------------
In general, the decision to crash the kernel belongs to the user, rather
than to the kernel developer.
Avoid panic()
*************
panic() should be used with care and primarily only during system boot.
panic() is, for example, acceptable when running out of memory during boot and
not being able to continue.
Use WARN() rather than BUG()
****************************
Do not add new code that uses any of the BUG() variants, such as BUG(),
BUG_ON(), or VM_BUG_ON(). Instead, use a WARN*() variant, preferably
WARN_ON_ONCE(), and possibly with recovery code. Recovery code is not
required if there is no reasonable way to at least partially recover.
"I'm too lazy to do error handling" is not an excuse for using BUG(). Major
internal corruptions with no way of continuing may still use BUG(), but need
good justification.
Use WARN_ON_ONCE() rather than WARN() or WARN_ON()
**************************************************
WARN_ON_ONCE() is generally preferred over WARN() or WARN_ON(), because it
is common for a given warning condition, if it occurs at all, to occur
multiple times. This can fill up and wrap the kernel log, and can even slow
the system enough that the excessive logging turns into its own, additional
problem.
Do not WARN lightly
*******************
WARN*() is intended for unexpected, this-should-never-happen situations.
WARN*() macros are not to be used for anything that is expected to happen
during normal operation. These are not pre- or post-condition asserts, for
example. Again: WARN*() must not be used for a condition that is expected
to trigger easily, for example, by user space actions. pr_warn_once() is a
possible alternative, if you need to notify the user of a problem.
Do not worry about panic_on_warn users
**************************************
A few more words about panic_on_warn: Remember that ``panic_on_warn`` is an
available kernel option, and that many users set this option. This is why
there is a "Do not WARN lightly" writeup, above. However, the existence of
panic_on_warn users is not a valid reason to avoid the judicious use
WARN*(). That is because, whoever enables panic_on_warn has explicitly
asked the kernel to crash if a WARN*() fires, and such users must be
prepared to deal with the consequences of a system that is somewhat more
likely to crash.
Use BUILD_BUG_ON() for compile-time assertions
**********************************************
The use of BUILD_BUG_ON() is acceptable and encouraged, because it is a
compile-time assertion that has no effect at runtime.
Appendix I) References
----------------------
The C Programming Language, Second Edition
by Brian W. Kernighan and Dennis M. Ritchie.
Prentice Hall, Inc., 1988.
ISBN 0-13-110362-8 (paperback), 0-13-110370-9 (hardback).
The Practice of Programming
by Brian W. Kernighan and Rob Pike.
Addison-Wesley, Inc., 1999.
ISBN 0-201-61586-X.
GNU manuals - where in compliance with K&R and this text - for cpp, gcc,
gcc internals and indent, all available from https://www.gnu.org/manual/
WG14 is the international standardization working group for the programming
language C, URL: http://www.open-std.org/JTC1/SC22/WG14/
Kernel CodingStyle, by greg@kroah.com at OLS 2002:
http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
문서의 목적과 들여쓰기
1-97이 문서는 Linux 커널에서 선호하는 코딩 형식을 간결하게 설명한다. 코딩 스타일은 개인 취향의 문제가 될 수 있지만, 커널은 여러 사람이 오랫동안 함께 수정하는 코드이므로 하나의 일관된 형식을 사용해야 한다. GNU 코딩 표준을 읽고 혼란스러웠다면 그 내용을 잊고 이 문서를 따르라는 도입부의 농담도 원문의 어조 그대로 이해하면 된다.
들여쓰기는 탭 문자이며 탭 너비는 8자다. 8자는 우연히 정한 값이 아니다. 조건문과 반복문이 여러 단계 겹치면 코드가 화면 오른쪽으로 빠르게 밀려나므로, 함수가 지나치게 복잡해졌다는 사실이 눈에 띈다. 들여쓰기가 세 단계보다 깊어졌다면 하위 동작을 별도 함수로 나누는 편이 낫다.
switch 문의 case 레이블은 switch와 같은 열에 둔다. 논리적으로는 case가 switch 내부에 있지만, 8자 탭을 사용하는 환경에서는 이 배치가 각 분기와 분기 본문을 가장 분명하게 구별한다.
switch (suffix) {
case 'G':
case 'g':
mem <<= 30;
break;
case 'M':
case 'm':
mem <<= 20;
break;
case 'K':
case 'k':
mem <<= 10;
fallthrough;
default:
break;
}
한 줄에 문장을 두 개 이상 쓰지 않는다. 아래 첫 예제는 do_this()만 조건에 포함되고 다음 문장은 항상 실행되지만, 화면에서는 둘 다 조건에 속한 것처럼 보인다. 두 번째 예제처럼 콤마 연산자로 중괄호를 피하는 방식도 읽는 사람에게 실행 경계를 숨긴다.
/* 잘못된 예 */
if (condition) do_this;
do_something_everytime;
/* 이 방법으로 중괄호를 피하지 않는다. */
if (condition)
do_this(), do_that();
/* 여러 문장은 명시적인 블록으로 묶는다. */
if (condition) {
do_this();
do_that();
}
복잡한 표현식과 여러 대입을 한 줄에 압축하지 않는다. 컴파일러가 이해할 수 있다는 사실보다 사람이 코드를 즉시 검토할 수 있는지가 중요하다. 주석, 문서, Kconfig처럼 탭이 적절하지 않은 영역을 제외하면 들여쓰기에 공백을 사용하지 않으며, 줄 끝 공백도 남기지 않는다.
긴 줄과 문자열 나누기
98-119코딩 스타일의 목적은 읽기 쉽고 유지보수하기 쉬운 코드를 만드는 것이다. 한 줄은 가급적 80열을 넘기지 않는다. 다만 줄을 억지로 나누어 의미 단위가 깨지거나 검색과 이해가 오히려 어려워진다면, 약간 긴 줄을 허용하는 편이 낫다.
줄을 나눌 때 이어지는 부분은 원래 줄보다 짧고 오른쪽에 놓여야 한다. 함수 인수는 여는 괄호 다음 위치에 맞추어 정렬한다. 이 원칙은 C 소스뿐 아니라 헤더 파일에도 적용한다.
printk 계열이 출력하는 사용자 가시 문자열은 여러 줄의 문자열 리터럴로 쪼개지 않는다. 커널 로그의 정확한 문구를 grep으로 찾는 일이 많기 때문에, 소스에서 검색 가능한 하나의 문자열로 유지해야 한다.
중괄호와 공백
120-305커널은 K&R 형식을 따른다. 함수가 아닌 블록의 여는 중괄호는 제어문의 마지막에 두고, 닫는 중괄호는 그 블록을 시작한 문장과 같은 들여쓰기 열의 첫 위치에 둔다.
if (x is true) {
we do y
}
switch (action) {
case KOBJ_ADD:
return "add";
case KOBJ_REMOVE:
return "remove";
case KOBJ_CHANGE:
return "change";
default:
return NULL;
}
함수 정의는 예외다. 함수의 여는 중괄호는 함수 이름 다음 줄의 첫 열에 둔다. 이 규칙은 K&R의 오랜 관례다.
int function(int x)
{
body of function
}
닫는 중괄호는 보통 한 줄을 단독으로 차지한다. 단, 같은 제어 구문이 계속되는 do-while의 while이나 if문의 else는 닫는 중괄호와 같은 줄에 둔다.
do {
body of do-loop
} while (condition);
if (x == y) {
..
} else if (x > y) {
...
} else {
....
}
조건문이나 반복문 본문이 정말로 단순한 한 문장이면 중괄호를 생략할 수 있다. if와 else 가운데 어느 한쪽이 여러 문장이라 중괄호가 필요하다면 양쪽 모두에 중괄호를 사용한다. 반복문 안에 조건문처럼 하위 제어 흐름이 들어가면 바깥 반복문에도 중괄호를 사용해 범위를 분명히 한다.
if (condition)
action();
if (condition)
do_this();
else
do_that();
if (condition) {
do_this();
do_that();
} else {
otherwise();
}
while (condition) {
if (test)
do_something();
}
키워드 if, switch, case, for, do, while 뒤에는 공백을 둔다. 함수처럼 보이는 sizeof, typeof, alignof, __attribute__ 뒤에는 공백을 두지 않는다. 괄호 안쪽에는 공백을 넣지 않는다. 따라서 sizeof(struct file)은 맞고 sizeof( struct file )은 틀리다.
포인터 선언의 별표는 자료형이 아니라 변수명이나 함수명 쪽에 붙인다. char *linux_banner, char *match_strdup(...) 형식을 사용한다. =, +, -, <, >, *, /, %, |, &, ^, <=, >=, ==, !=, ?와 : 같은 이항·삼항 연산자 양쪽에는 공백을 둔다.
단항 &, *, +, -, ~, !와 sizeof, typeof, alignof, __attribute__, defined 뒤에는 공백을 두지 않는다. 전위·후위 ++와 -- 주위에도 공백을 두지 않으며, 구조체 멤버 연산자 .와 -> 주위에도 공백을 두지 않는다.
줄 끝 공백은 대부분의 편집기에서 보이지 않지만 패치를 불필요하게 오염시키고 이후 변경의 문맥 일치를 깨뜨린다. 일부 Git 설정은 자동으로 제거할 수 있으나, 이미 존재하는 줄 끝 공백을 기계적으로 모두 고치면 관련 없는 변경이 커질 수 있으므로 주의한다.
이름 짓기
306-358C는 이름을 짓는 언어다. 지역 변수는 짧고 용도가 즉시 드러나는 이름을 쓴다. 반복 횟수에는 i, 임시 값에는 tmp처럼 관례가 분명한 이름이 긴 CamelCase 이름보다 낫다. 혼합 대소문자 이름은 커널에서 권장하지 않는다.
반대로 전역 함수와 전역 변수는 무엇을 하는지 설명할 수 있는 이름이 필요하다. 전역 심볼 자체도 꼭 필요한 경우에만 만든다. 자료형을 이름에 반복하는 헝가리안 표기법은 컴파일러가 이미 알고 있는 정보를 중복하므로 사용하지 않는다.
새 코드에서는 master/slave와 blacklist/whitelist 용어를 피한다. 문맥에 따라 아래와 같이 역할을 실제로 설명하는 조합을 선택한다.
| 피할 표현 | 권장 대안 |
|---|---|
| master / slave | primary 또는 main / secondary, replica 또는 subordinate |
| master / slave | initiator 또는 requester / target 또는 responder |
| master / slave | controller 또는 host / device, worker 또는 proxy |
| master / slave | leader / follower, director / performer |
| blacklist / whitelist | denylist / allowlist, blocklist / passlist |
사용자 공간 ABI/API를 유지해야 하거나, 2020년 기준으로 이미 공개된 하드웨어·프로토콜 규격이 특정 용어를 의무화한 경우에는 예외가 될 수 있다. 이때도 새 내부 이름까지 무비판적으로 같은 표현으로 확장하지 않는다.
typedef 사용 기준
359-442구조체나 포인터를 감추기 위해 typedef를 습관적으로 사용하지 않는다. vps_t a보다 struct virtual_container *a가 객체의 종류와 포인터 여부를 코드에 직접 드러낸다. 구조체 태그를 숨기면 선언만 보고 실제 자료 구조를 알기 어렵고, 포인터 typedef는 값과 참조의 차이까지 감춘다.
/* 피해야 할 형태 */
vps_t a;
/* 구조를 명시하는 형태 */
struct virtual_container *a;
typedef가 정당한 첫 번째 경우는 pte_t처럼 내용을 이식 가능한 방법으로 직접 해석할 수 없고 반드시 접근자 함수를 거쳐야 하는 완전히 불투명한 객체다. 그러나 불투명화와 접근자 함수 자체가 좋은 설계라는 뜻은 아니다. 페이지 테이블 엔트리는 아키텍처마다 표현이 달라 직접 접근할 공통 정보가 전혀 없기 때문에 예외가 성립한다.
두 번째는 int인지 long인지 혼동하기 쉬운 정수 표현을 추상화하는 경우다. 단순히 unsigned long에 myflags_t라는 새 이름을 붙이는 것은 이유가 없다. 설정에 따라 unsigned int와 unsigned long 사이에서 실제 표현이 달라져야 한다면 typedef가 그 차이를 격리할 수 있다.
typedef unsigned long myflags_t;
세 번째는 sparse가 정적 형 검사를 수행할 수 있도록 실제로 새로운 타입을 만드는 경우다. 네 번째는 u8, u16, u32, u64 및 부호 있는 대응형처럼 표준 C99 정수형과 동일하지만 Linux 코드에서 널리 쓰이는 타입이다. 새 코드에서 반드시 Linux 형을 써야 하는 것은 아니며, 기존 파일을 수정할 때는 그 코드가 이미 선택한 표기를 따른다.
다섯 번째는 사용자 공간과 공유되는 구조체다. 사용자 공간에 C99 타입 사용을 강제할 수 없고 커널 내부 u32를 그대로 노출할 수도 있으므로, UAPI 구조체에는 __u32 같은 타입을 사용한다. 이 예외들에 해당하지 않는다면 포인터나 직접 접근 가능한 구조체에 typedef를 만들지 않는다.
함수의 크기, 선언과 속성 순서
443-525함수는 짧고 한 가지 작업만 수행해야 한다. 이상적인 함수는 80열 24행 화면 한두 개 안에서 전체를 볼 수 있다. 허용 가능한 길이는 복잡도와 들여쓰기 깊이에 반비례한다. 단순한 switch가 많은 case를 갖는 함수는 길어도 이해할 수 있지만, 중첩된 복잡한 함수는 더 짧아야 한다.
별도 이름으로 설명할 수 있는 복잡한 부분은 보조 함수로 분리한다. 컴파일러는 필요하면 이를 인라인으로 최적화할 수 있고, 사람이 읽고 검토하기도 쉬워진다. 지역 변수도 보통 5개에서 10개를 넘기지 않는 것이 좋다. 변수가 많다면 함수가 너무 많은 상태를 한꺼번에 다루고 있는지 살펴본다.
함수 사이에는 빈 줄 하나를 둔다. EXPORT_SYMBOL 계열 매크로는 함수의 닫는 중괄호 바로 다음 줄에 둔다. 함수 원형에는 인수 이름을 포함해야 하며, 함수 선언에 extern을 붙이지 않는다.
int system_is_up(void)
{
return system_state == SYSTEM_RUNNING;
}
EXPORT_SYMBOL(system_is_up);
함수 선언 요소는 저장 클래스, 저장 클래스 속성, 반환형, 반환값 속성, 함수 이름, 이름을 포함한 매개변수, 매개변수 속성, 동작 속성 순으로 배치한다. 선언 예는 다음과 같다.
__init void * __must_check action(enum magic value, size_t size, u8 count,
char *fmt, ...) __printf(4, 5) __malloc;
저장 클래스에는 static과 extern이, 저장 클래스 속성에는 __init과 __cold가, 반환값 속성에는 __must_check가 해당한다. __printf 같은 매개변수 속성과 __malloc 같은 함수 동작 속성은 뒤쪽에 놓인다. 함수 정의에서는 컴파일러 제약 때문에 매개변수 속성을 저장 클래스 속성 다음으로 이동한다.
static __always_inline __init __printf(4, 5) void * __must_check action(enum magic value,
size_t size, u8 count, char *fmt, ...) __malloc
{
...
}
공통 종료 경로와 goto
526-597goto는 무조건 피해야 하는 문법이 아니다. 함수 중간 여러 지점에서 동일한 자원을 정리해야 한다면 하나의 종료 경로로 모으는 것이 중복과 누락을 줄인다. 정리할 것이 없는 단순 오류라면 바로 return하는 편이 낫다.
레이블은 err1, err2처럼 위치만 나타내지 말고 out_free_buffer처럼 수행할 동작을 설명해야 한다. 공통 종료 경로는 본문 중첩을 줄이고, 정리 코드를 한곳에 모아 수정 시 한 경로만 고쳐도 되게 한다.
int fun(int a)
{
int result = 0;
char *buffer;
buffer = kmalloc(SIZE, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
if (condition1) {
while (loop1) {
...
}
result = 1;
goto out_free_buffer;
}
...
out_free_buffer:
kfree(buffer);
return result;
}
단일 err 레이블에서 foo->bar와 foo를 모두 해제하면 bar 할당 전에 실패한 경로도 초기화되지 않은 bar를 해제할 수 있다. 각 자원이 실제로 확보된 시점에 맞춰 레이블을 나누고, 아래쪽 정리 단계로 자연스럽게 떨어지게 해야 한다.
/* 잘못된 정리 경로 */
err:
kfree(foo->bar);
kfree(foo);
return ret;
/* 할당 단계와 대응하는 정리 경로 */
err_free_bar:
kfree(foo->bar);
err_free_foo:
kfree(foo);
return ret;
종료 경로가 맞는지는 각 할당과 초기화 단계에서 실패를 강제로 주입해 검증한다. 정상 경로만 실행해서는 이중 해제, 미할당 객체 해제, 참조 누수 같은 오류를 찾기 어렵다.
주석
598-640주석은 코드가 무엇을 하는지 그대로 읽어 주기보다 왜 그렇게 해야 하는지를 설명해야 한다. 복잡한 함수의 각 줄에 주석을 붙이는 대신 함수를 단순화하고, 함수 머리말에서 전체 목적과 제약을 설명한다.
외부에 공개되는 커널 API는 kernel-doc 형식을 사용한다. 코드만 반복하는 상투적인 주석은 피한다. 여러 줄 주석은 왼쪽에 별표 열을 두는 커널 형식을 일관되게 사용한다.
/*
* This is the preferred style for multi-line
* comments in the Linux kernel source code.
* Please use it consistently.
*
* Description: A column of asterisks on the left side,
* with beginning and ending almost-blank lines.
*/
함수 내부의 동작뿐 아니라 중요한 자료 구조와 필드의 의미도 설명한다. 여러 변수를 한 선언에 묶으면 각 변수 옆에 의미를 적기 어려우므로, 주석이 필요한 데이터는 한 줄에 하나씩 선언한다.
편집기와 자동 정렬 도구
641-733일부 편집기의 기본 C 들여쓰기는 커널 형식과 맞지 않는다. 아래 Emacs 설정은 탭 기반 인수 정렬, 8자 기본 들여쓰기, case 레이블과 전처리기 매크로 정렬, 줄 끝 공백 표시 등을 Linux 소스 트리용 디렉터리 클래스에 적용하는 원문의 예다.
(defun c-lineup-arglist-tabs-only (ignored)
"Line up argument lists by tabs, not spaces"
(let* ((anchor (c-langelem-pos c-syntactic-element))
(column (c-langelem-2nd-pos c-syntactic-element))
(offset (- (1+ column) anchor))
(steps (floor offset c-basic-offset)))
(* (max steps 1)
c-basic-offset)))
(dir-locals-set-class-variables
'linux-kernel
'((c-mode . (
(c-basic-offset . 8)
(c-label-minimum-indentation . 0)
(c-offsets-alist . (
(arglist-close . c-lineup-arglist-tabs-only)
(arglist-cont-nonempty .
(c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only))
(arglist-intro . +)
(brace-list-intro . +)
(c . c-lineup-C-comments)
(case-label . 0)
(comment-intro . c-lineup-comment)
(cpp-define-intro . +)
(cpp-macro . -1000)
(cpp-macro-cont . +)
(defun-block-intro . +)
(else-clause . 0)
(func-decl-cont . +)
(inclass . +)
(inher-cont . c-lineup-multi-inher)
(knr-argdecl-intro . 0)
(label . -1000)
(statement . 0)
(statement-block-intro . +)
(statement-case-intro . +)
(statement-cont . +)
(substatement . +)
))
(indent-tabs-mode . t)
(show-trailing-whitespace . t)
))))
(dir-locals-set-directory-class
(expand-file-name "~/src/linux-trees")
'linux-kernel)
indent 도구를 쓴다면 -kr -i8 옵션 또는 scripts/Lindent를 사용할 수 있다. 다만 자동 정렬은 나쁜 프로그램 구조를 좋은 코드로 바꾸지 못한다. clang-format은 코드 재정렬, include 순서 정리, 변수 정렬, 텍스트 재배치와 같은 작업을 지원하며 관련 사용법은 Documentation/dev-tools/clang-format.rst에 있다. 여러 편집기에서 공통 설정을 읽게 하려면 EditorConfig도 사용할 수 있다.
Kconfig 파일
734-762Kconfig의 config 아래 항목은 탭 한 단계로 들여쓰고, help 본문은 탭 다음에 공백 두 칸을 더 둔다. 다음 AUDIT 예제가 기준 형식을 보여 준다.
config AUDIT
bool "Auditing support"
depends on NET
help
Enable auditing infrastructure that can be used with another
kernel subsystem, such as SELinux (which requires this for
logging of avc messages output). Does not do system-call
auditing without CONFIG_AUDITSYSCALL.
데이터 손상처럼 위험한 동작을 허용하는 옵션의 프롬프트에는 DANGEROUS를 명시한다. 사용자는 메뉴만 보고도 위험을 알아야 한다.
config ADFS_FS_RW
bool "ADFS write support (DANGEROUS)"
depends on ADFS_FS
...
자료 구조의 참조 수명
763-794객체를 만들고 없애는 단일 스레드 문맥 밖에서도 찾을 수 있는 자료 구조라면 참조 계수가 필요하다. 다른 실행 주체가 객체를 발견할 수 있는데 수명 확보 절차가 없다면, 발견 직후 다른 CPU가 객체를 해제하는 use-after-free 경쟁이 생긴다.
잠금과 참조 계수는 서로 대체할 수 없다. 잠금은 객체 내용의 일관성을 보호하고, 참조 계수는 객체 메모리가 계속 존재하도록 보장한다. 객체를 잠그려면 먼저 그 객체를 안전하게 참조할 수 있어야 한다.
복잡한 객체는 두 단계 참조 계수를 사용할 수 있다. mm_struct의 mm_users는 주소 공간을 사용하는 사용자 수를, mm_count는 구조체 자체를 붙잡는 내부 참조를 센다. super_block의 s_count와 s_active도 외부 발견 가능성과 활성 사용을 서로 다른 계층에서 관리한다.
핵심 질문은 '다른 스레드가 이 객체를 어떻게 찾고, 찾은 순간부터 어떤 참조가 해제를 막는가'다. 이 질문에 답할 수 없다면 잠금이 있더라도 객체 수명 설계에는 결함이 있다.
매크로, enum과 RTL
795-898상수 매크로와 enum 레이블은 대문자로 쓴다. 서로 관련된 상수 집합은 enum으로 묶으면 컴파일러와 디버거가 의미를 더 잘 보존한다. 함수처럼 호출되는 매크로는 소문자 이름을 사용할 수 있지만, 형 검사와 디버깅이 가능한 static inline 함수를 우선한다.
#define CONSTANT 0x12345
여러 문장을 포함하는 매크로는 do { ... } while (0)로 감싼다. 이렇게 해야 호출자가 일반 함수처럼 뒤에 세미콜론을 붙일 수 있고, if-else 안에서도 하나의 문장으로 동작한다.
#define macrofun(a, b, c) \
do { \
if (a == 5) \
do_this(b, c); \
} while (0)
사용하지 않는 매개변수를 처리하려고 아무 일도 하지 않는 매크로를 만들기보다 빈 static inline 함수를 사용한다. 컴파일러는 인수의 타입을 검사하고 호출 코드를 제거한다. 아래처럼 인수를 void로 캐스팅하는 매크로는 가급적 피한다.
static inline void fun(struct foo *foo)
{
}
/* 가능하면 피하고 static inline 함수를 사용한다. */
#define macrofun(foo) do { (void) (foo); } while (0)
호출 함수에서 return이나 break를 실행하는 제어 흐름 매크로는 호출부만 읽어서는 흐름을 알 수 없으므로 피한다. 아래 FOO는 평범한 함수 호출처럼 보이지만 호출한 함수 전체에서 반환한다.
#define FOO(x) \
do { \
if (blah(x) < 0) \
return -EBUGGERED; \
} while (0)
매크로가 호출자 지역 변수에 몰래 의존해서도 안 된다. #define FOO(val) bar(index, val)처럼 index를 인수로 받지 않으면 호출부 문맥에 숨은 결합이 생긴다. 매크로 인수는 여러 번 평가될 수 있으므로 l-value로 사용하지 말고, 표현식과 각 인수는 연산자 우선순위가 바뀌지 않게 괄호로 감싼다.
#define FOO(val) bar(index, val)
#define CONSTANT 0x4000
#define CONSTEXP (CONSTANT | 3)
문장 표현식 매크로 내부의 임시 이름은 호출자 이름과 충돌할 수 있다. ret 대신 __foo_ret처럼 매크로에 고유한 접두사를 붙인다. 아래 원문 예제의 ret는 충돌 가능성을 보여 주기 위한 피해야 할 형태다.
#define FOO(x) \
({ \
typeof(x) ret; \
ret = calc_ret(x); \
(ret); \
})
전처리기 세부 규칙은 GNU cpp 매뉴얼의 매크로 절을 참고한다. GCC 내부 표현인 RTL은 컴파일러 내부를 다루는 경우의 별도 주제이며, 커널 C 코드의 가독성을 위해 매크로로 복잡한 컴파일러 동작을 흉내 내서는 안 된다.
커널 메시지 출력
899-934커널 메시지는 맞춤법을 지키고 짧고 분명하며 중의적이지 않게 쓴다. 문장 끝 마침표는 반드시 필요하지 않다. 여러 메시지를 구별하려고 괄호 안에 임의의 번호를 붙이는 방식은 사용자에게 의미가 없으므로 피한다.
장치와 연결된 메시지는 dev_err, dev_warn, dev_info처럼 장치 문맥을 자동으로 포함하는 함수를 사용한다. 장치가 없는 전역 문맥에서는 pr_notice, pr_info, pr_warn, pr_err 등을 사용한다.
드라이버는 정상 동작 중 조용해야 한다. 시스템에 잘못된 일이 생긴 것이 아니라 진단용 정보라면 dev_dbg 또는 pr_debug를 사용한다. 이 호출은 DEBUG가 정의되거나 CONFIG_DYNAMIC_DEBUG가 활성화된 경우가 아니면 컴파일 결과에서 제거된다. 더 상세한 로그에는 VERBOSE_DEBUG와 dev_vdbg를 사용할 수 있다.
Kconfig 디버그 옵션은 필요하면 -DDEBUG를 컴파일 옵션에 추가할 수 있고, 특정 파일에서만 #define DEBUG를 둘 수도 있다. 디버그 조건문 안에서 항상 출력해야 하는 메시지라면 printk(KERN_DEBUG ...)를 직접 사용할 수 있다.
메모리 할당
935-975일반적인 커널 할당 함수에는 kmalloc, kzalloc, kmalloc_array, kcalloc, vmalloc, vzalloc이 있다. 각 함수의 주소 연속성, 초기화 여부와 수면 가능 문맥은 메모리 할당 문서를 함께 확인해야 한다.
구조체를 할당할 때는 자료형 이름을 반복하지 않고 포인터가 가리키는 객체의 크기를 사용한다. p = kmalloc(sizeof(*p), ...)는 선언 형식이 바뀌어도 할당 크기가 자동으로 따라가며, 긴 구조체 이름을 반복하지 않아 읽기 쉽다. kmalloc 반환값은 void 포인터이므로 캐스팅하지 않는다.
p = kmalloc(sizeof(*p), ...);
배열은 n * sizeof(...)를 직접 계산해 kmalloc에 넘기지 말고 kmalloc_array를 사용한다. 0으로 초기화된 배열은 kcalloc을 사용한다. 두 함수는 곱셈 오버플로를 검사하고 크기를 표현할 수 없으면 NULL을 반환한다.
p = kmalloc_array(n, sizeof(...), ...);
p = kcalloc(n, sizeof(...), ...);
__GFP_NOWARN 없이 일반 할당 함수를 호출하면 실패 시 할당기가 이미 스택 덤프를 출력한다. NULL을 받았다는 이유로 호출부에서 같은 실패 메시지를 추가하면 로그만 중복되므로 별도 오류 메시지를 출력할 필요가 없다.
inline의 과도한 사용
977-1002inline은 함수를 자동으로 빠르게 만드는 마법의 옵션이 아니다. 매크로를 타입 안전한 함수로 바꾸는 경우처럼 적절한 용도가 있지만, 남용하면 같은 함수 본문이 여러 호출 지점에 복제되어 커널 이미지가 커진다.
커진 코드는 CPU 명령 캐시 점유를 늘리고 page cache에 쓸 수 있는 메모리를 줄여 시스템 전체를 느리게 할 수 있다. 원문은 page cache miss로 디스크 탐색이 발생하면 약 5ms가 걸릴 수 있고, 그 시간에는 매우 많은 CPU 사이클이 들어간다는 예로 코드 크기 비용을 설명한다.
경험칙으로 코드가 세 줄보다 긴 함수에는 inline을 붙이지 않는다. 단, 매개변수가 컴파일 시간 상수이고 그 값 때문에 함수 대부분이 제거된다는 것을 확실히 아는 경우는 예외다. kmalloc() 인라인 함수가 대표적인 예다.
static 함수가 한 번만 호출되므로 inline이 항상 이득이라는 주장도 유지보수 관점에서는 충분하지 않다. GCC는 이런 함수를 스스로 인라인할 수 있다. 나중에 두 번째 호출자가 생겼을 때 inline을 제거해야 하는 부담이, 컴파일러가 이미 할 최적화를 강제하는 작은 이득보다 크다.
함수 이름과 반환값
1005-1037성공과 실패를 나타내는 반환값은 주로 두 형식이다. 오류 코드 정수는 음수 -Exxx가 실패이고 0이 성공이다. 성공 여부를 나타내는 불리언은 0이 실패이고 0이 아닌 값이 성공이다. 두 규약을 뒤섞으면 조건식을 반대로 해석하는 찾기 어려운 버그가 생긴다.
함수 이름이 동작이나 명령형이면 오류 코드 정수를 반환한다. 함수 이름이 어떤 조건을 묻는 술어라면 성공 여부를 나타내는 bool을 반환한다.
add_work()는 '작업을 추가하라'는 명령이므로 성공 시 0, 실패 시 -EBUSY를 반환한다. pci_dev_present()는 '일치하는 PCI 장치가 존재하는가'라는 술어이므로 찾으면 1, 찾지 못하면 0을 반환한다.
EXPORT된 함수와 모든 공개 함수는 이 규약을 따라야 한다. private static 함수에도 같은 규칙을 적용하는 것을 권장한다. 계산 자체의 결과를 반환하는 함수는 이 규칙의 대상이 아니며, 포인터 함수가 NULL 또는 ERR_PTR로 실패를 표현하듯 정상 범위를 벗어난 값으로 오류를 나타낼 수 있다.
bool 사용
1040-1068Linux 커널의 bool은 C99 _Bool의 별칭이다. bool 값은 0 또는 1로만 평가되며, bool로 변환하면 자동으로 false 또는 true가 된다. 따라서 bool 값에 !!를 다시 적용할 필요가 없고, 값에는 숫자 1과 0 대신 true와 false를 사용한다.
함수 반환형과 스택 지역 변수에는 의미가 맞으면 bool을 자유롭게 사용할 수 있다. 참과 거짓을 저장하는 int보다 의도를 분명히 하므로 권장된다.
그러나 bool의 크기와 정렬은 대상 아키텍처에 따라 달라질 수 있다. 캐시 라인 배치나 구조체 크기가 중요한 자료 구조에는 bool을 사용하지 않는다. 참·거짓 필드가 많다면 1비트 bitfield로 모으거나 u8 같은 고정 폭 타입을 고려한다.
함수 인수에 true/false가 여러 개 나열되면 호출부만 보고 각 값의 뜻을 알기 어렵다. 이 경우 하나의 비트 flags 인수로 묶으면 더 읽기 쉬울 수 있다. 그 밖의 제한적인 구조체 필드와 인수에서는 bool이 가독성을 높인다.
기존 커널 매크로 재사용
1070-1090include/linux/kernel.h에는 흔한 계산을 안전하고 일관되게 수행하는 매크로가 이미 있다. 배열 원소 수를 직접 sizeof 식으로 다시 만들지 말고 ARRAY_SIZE를 사용한다.
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
구조체 특정 멤버의 크기는 sizeof_field를 사용한다. 엄격한 타입 검사를 수행하는 min과 max도 제공된다. 비슷한 매크로를 새로 쓰기 전에 기존 헤더에 같은 기능이 있는지 확인한다.
#define sizeof_field(t, f) (sizeof(((t*)0)->f))
소스 파일의 editor modeline 금지
1093-1124Emacs와 Vim을 비롯한 편집기는 소스 파일 안의 특별한 표식을 읽어 모드, 들여쓰기와 빌드 명령을 바꿀 수 있다. 원문은 다음 세 형태를 예로 든다.
-*- mode: c -*-
/*
Local Variables:
compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"
End:
*/
/* vim:set sw=8 noet */
이런 modeline을 커널 소스에 넣지 않는다. 개발자는 각자 편집기 설정과 사용자 정의 모드를 가지고 있으며, 저장소의 소스 파일이 개인 환경을 덮어써서는 안 된다. 들여쓰기와 모드 설정을 위한 표식도 모두 이 금지 대상이다.
인라인 어셈블리
1127-1156아키텍처 전용 코드에서 CPU 또는 플랫폼 기능과 연결하려면 인라인 어셈블리가 필요할 수 있다. 필요한 경우에는 사용하되, C로 같은 작업을 할 수 있다면 불필요한 어셈블리를 쓰지 않는다. 가능한 하드웨어 접근도 C 접근자와 헬퍼로 표현한다.
반복되는 짧은 어셈블리 조각은 C 매개변수를 받는 단순한 헬퍼 함수로 감싼다. 크고 복잡한 어셈블리 함수는 .S 파일에 두고 C 헤더에 대응하는 원형을 선언한다. 어셈블리로 구현한 함수의 C 원형에는 asmlinkage를 사용한다.
GCC가 부수 효과를 알아채지 못해 asm 문을 제거할 가능성이 있을 때는 volatile이 필요할 수 있다. 그러나 모든 asm에 기계적으로 volatile을 붙이면 컴파일러 최적화를 제한하므로 실제 필요성을 판단해야 한다.
하나의 asm 문에 여러 명령을 쓸 때는 명령마다 별도 문자열 줄을 사용하고, 마지막을 제외한 각 문자열을 \n\t로 끝낸다. 그러면 생성된 어셈블리에서도 다음 명령이 올바르게 줄 바꿈되고 들여쓰기된다.
asm ("magic %reg1, #42\n\t"
"more_magic %reg2, %reg3"
: /* outputs */ : /* inputs */ : /* clobbers */);
조건부 컴파일
1159-1205가능하면 .c 파일 안에 #if와 #ifdef를 두지 않는다. 전처리 조건은 코드를 읽기 어렵게 하고 C의 제어 흐름을 끊는다. 대신 헤더에서 설정이 켜졌을 때의 실제 함수와 꺼졌을 때의 no-op stub을 각각 정의하고, .c 파일은 함수를 무조건 호출하게 한다. 컴파일러는 빈 stub 호출을 제거하므로 실행 결과와 비용은 동일하다.
함수 일부나 표현식 일부를 조건부로 지우기보다 함수 전체를 컴파일 대상에서 제외한다. 표현식 중간에 ifdef가 필요하다면 해당 부분을 보조 함수로 분리하고 그 함수 정의에 조건을 적용한다.
특정 설정에서만 사용되지 않을 수 있는 함수나 변수는 전처리 조건으로 선언 자체를 감싸기보다 __maybe_unused로 표시할 수 있다. 모든 설정에서 항상 사용되지 않는 코드라면 표시로 숨기지 말고 삭제한다.
코드 안에서는 가능한 경우 IS_ENABLED로 Kconfig 심볼을 C 불리언 식으로 바꾸어 일반 if문에 사용한다.
if (IS_ENABLED(CONFIG_SOMETHING)) {
...
}
컴파일러는 상수 조건을 접어 설정에 맞는 블록만 남기므로 런타임 오버헤드가 없다. 동시에 C 컴파일러가 블록 내부의 문법, 타입과 심볼 참조를 검사할 수 있다. 단, 설정이 꺼지면 존재하지 않는 심볼을 블록 안에서 참조하는 경우에는 여전히 #ifdef가 필요하다.
몇 줄을 넘는 #if 또는 #ifdef 블록의 끝에는 #endif와 같은 줄에 원래 조건을 주석으로 적는다.
#ifdef CONFIG_SOMETHING
...
#endif /* CONFIG_SOMETHING */
커널을 함부로 중단하지 않기
1208-1268커널을 중단할지 결정할 권한은 일반적으로 커널 개발자가 아니라 사용자에게 있다. panic()은 매우 신중하게 사용하며 주로 부팅 중 더 진행할 방법이 없을 때만 허용한다. 예를 들어 부팅 과정에서 메모리가 고갈되어 시스템을 계속 초기화할 수 없다면 panic이 타당할 수 있다.
새 코드에는 BUG(), BUG_ON(), VM_BUG_ON() 같은 BUG 변형을 추가하지 않는다. 대신 WARN 계열, 가능하면 WARN_ON_ONCE()를 사용하고 합리적인 복구가 가능하면 복구 경로를 제공한다. 적어도 부분 복구조차 불가능한 경우에는 복구 코드가 필수는 아니지만, 오류 처리를 작성하기 귀찮다는 이유로 BUG를 선택할 수는 없다. 계속 실행할 방법이 없는 중대한 내부 손상에만 충분한 근거와 함께 BUG가 남을 수 있다.
WARN()이나 WARN_ON()보다 WARN_ON_ONCE()를 일반적으로 선호한다. 한 번 발생한 경고 조건은 반복해서 발생하기 쉬우며, 동일한 경고가 로그를 가득 채우고 이전 로그를 밀어내거나 출력 자체가 시스템을 느리게 만드는 추가 문제를 일으킬 수 있다.
WARN 계열은 정상 동작에서는 절대로 일어나지 않아야 하는 예상 밖 내부 상태를 위한 것이다. 일반적인 사전·사후 조건 검사용 assert가 아니며, 사용자 공간 입력만으로 쉽게 발생할 수 있는 조건에 사용해서는 안 된다. 사용자에게 문제를 한 번 알릴 필요가 있다면 pr_warn_once()가 대안이 될 수 있다.
panic_on_warn을 켠 사용자가 있다는 이유로 필요한 WARN까지 피하지 않는다. 이 옵션을 활성화한 사용자는 WARN 발생 시 커널을 중단하라고 명시적으로 요청한 것이며, 그에 따라 시스템 중단 가능성이 커진다는 결과를 감수한다. 개발자는 WARN의 의미가 맞는지만 신중하게 판단한다.
컴파일 시간 단언에는 BUILD_BUG_ON()을 사용할 수 있고 사용을 권장한다. 이 검사는 빌드 단계에서 실패하며 런타임에는 아무 영향도 주지 않는다.
참고 문헌
1270-1290원문은 C 언어와 프로그래밍 관례를 위한 기본 참고 문헌으로 Brian W. Kernighan과 Dennis M. Ritchie의 The C Programming Language 2판, Brian W. Kernighan과 Rob Pike의 The Practice of Programming을 제시한다.
K&R 및 이 문서와 충돌하지 않는 범위에서 cpp, gcc, GCC internals와 indent의 GNU 매뉴얼도 참고한다. C 언어 국제 표준화 작업 그룹 WG14와 Greg Kroah-Hartman의 OLS 2002 Kernel CodingStyle 발표 자료가 함께 열거되어 있다.
8-character tab과 중첩 깊이
coding-style.rst:3-95Kernel indentation은 tab 하나당 8 character다. 큰 들여쓰기는 control block 경계를 명확히 하고, 세 단계보다 깊은 nesting이 생겼을 때 function 구조를 다시 나눠야 한다는 신호를 준다. Comment, documentation과 Kconfig를 제외한 code indentation에 space를 사용하지 않는다.
Switch와 case label은 같은 column에 둔다. 한 줄에 여러 statement나 assignment를 쓰지 않고 comma operator로 brace를 피하지 않는다. 여러 statement block에는 brace를 사용하며 trailing whitespace를 남기지 않는다.