리눅스 커널 코딩 스타일 페이지를 번역했더니 메모장 기준으로 655줄
, 5289단어
가 나왔다. 상당히 긴 내용이므로 필자는 이를 3장에 걸쳐 출간할 예정이다.
읽기 전 독자들이 알아둬야 할 내용과 주의사항에 대해 밝히도록 하겠다.
리눅스 커널 코딩 스타일 이라는 리눅스 공식 홈페이지의 내용을 번역한 것이다.
번역일은 2021
년 05
월 11
~ 13
일이다. 따라서 번역일 이후 문서의 개정이 이뤄졌을 수도 있다. 따라서 독자는 절대 필자의 번역 내용만을 맹신해선 안되고 원문도 같이 보는게 좋다.
필자는 가방끈이 매우 짧다. 필자의 영어 공부법은 매우 단순하다:
- 일단 그냥 읽는다. (
당연히 이해가 안됨
)- 모르는 단어가 해당 단어의
영영사전
을 읽는다. (Cambridge Dictionary
를 주로 이용)
*일반적인 경우
1-1. 일단 그냥영영사전
을 읽는다.
1-2. 모르는 단어가 나오면영영사ㅈ
... (재귀이므로 이하동문
)
*Worst case
: 영영사전 내용 자체가 이해가 안됨.
2-1.영한사전
도 같이 본다. (네이버 영한 사전
을 주로 이용)- 이어 붙여서 번역한다.
- 번역기에 돌려서
3번 과정
에서 잘못 해석했다 싶은 문맥을 바로 잡는다.
1번
에서 말했듯이 번역한 내용을 그대로 받아 들여선 안되고 원문을 한번 더 들여다 보는 것이 좋다. 언제나 의심하라. 의심은 진리로 이끈다.초벌 번역
에선 최대한 직역하고, 2차 번역
에선 직역하되 우리말 문맥에 맞추려 노력했다. 용례
가 다양한 경우 소괄호로 묶어 원어
또한 적어 두었다. (e.g.
file descriptor
는 파일 기술자
혹은 파일 서술자
등으로, statement
는 구문
, 문장
으로 번역이 가능므로 괄호를 쳐서 원어를 같이 적는다.)한글
로 옮기려 노력했다. line
의 경우 라인
이 아닌 행
으로, function header
의 경우에도 함수 헤더
가 아닌 함수 머리
와 같이 옮기려 노력했다.다만 block
의 경우 어떻게 해도 걸맞는 용어가 없어 이런 경우 발음대로 블록으로 옮겼다. 한마디로 옮길 수 있으면서도, 해석에 문제가 되지 않는다면 전부 옮겨 작성했다.line
)" 과 같이 괄호를 써서 원어를 같이 표기하고, 이후 등장하는 경우 괄호를 생략했다.잡담이 길었는데 여기까지 하고 본문으로 넘기겠다.
이 짧은 문서는 리눅스 커널에서 선호되는 코딩 스타일을 서술한다. 코딩 스타일은 매우 주관적이기에, 나는 모든 이에게 나의 관점을 강요하진 않을 것이다.
그러나, 이는 내가 관리해야 할 수 있는 모든 것에 대해 적용되고, 나는 이를 대부분의 것들에서 역시 선호한다. 그러니 여기에서 나온 관점을 한번씩 고려하길 바란다.
처음으로, 나는 GNU 코딩 스타일 표준 문서를 프린터로 출력하여, 읽지 않는
것을 추천한다. 그리고 이를 태워라. 이는 대단히 상징적인 행위이다.
어쨌든, 코딩 스타일은 다음과 같다:
탭은 8 문자
이고, 따라서 들여쓰기 역시 8 문자
이다. 여기에는 들여쓰기를 4개
(혹은 심지어 2개
!) 문자의 깊이로 시도하려는 이단적인 움직임이 있다. 이는 마치 PI
의 값을 3
으로 정의하려는 것과 유사하다.
근거(Rationale
): 들여쓰기, 그 배경에 있는 전체적인 아이디어는 블록(block
) 제어의 시작과 끝이 어디인지를 명료하게 정의하기 위함이다. 특히, 네가 20 시간
동안 모니터 앞에 죽치고 않아 있을 때, 만일 네가 더 큰 들여쓰기를 한다면, 들여쓰기가 어떻게 되어 있는지 더 쉽게 찾을 수 있을 것이다.
자 이제, 일부 사람들은 8 문자
로 들여쓰는 것은 코드를 오른쪽으로 너무 멀리가게 만들어서, 80 문자
터미널에선 읽기가 어렵다고 불평할 것이다. 그에 대한 답은 다음과 같다: 만일 네가 3 단계
이상의 들여쓰기를 필요로 한다면, 완전 망친 것이므로, 너는 프로그램을 고쳐야 할 것이다.
짧게 말해,
8 문자
들여쓰기는 코드를 더 읽기 쉽게 만들어주고, 네가 함수를 너무 깊게 중첩하는 것에 대한 주의를 주는 추가적인 이점을 가진다. 그 경고(과도한 들여쓰기
)에 주의하라.
switch 문
에서 복수(multiple
)의 들여쓰기 수준을 완화하기 위해 선호되는 방법은 하위 case
레이블을 2 단
으로 들여쓰는 대신 switch
와 같은 열에 두는 것이다. E.g
:
switch (suffix) { case 'G': case 'g': mem <<= 3; break; case 'M': case 'm': mem <<= 20; break; case 'K': case 'k': mem <<= 10; fallthrough; default: break; }
네가 무언가를 숨길 의도가 있지 않다면 복수의 구문(statement
)을 단행(single line
)에 놓지 마라:
if (condition) do_this; do_something_everytime;
중괄호 사용을 피하기 위해 콤마들을 사용하지 마라:
if (condtion) do_this(), do_that();
복수의 구문을 위해 항상 중괄호(braces
)를 사용하라:
if (condition) { do_this(); do_that(); }
복수의 대입(assignment
)을 단행에 놓지 마라.
커널 코딩 스타일은 매우 단순하다. 교활한(
tricky
) 표현식들을 피하라.
Kconfig
을 제외한, 주석(comments
)과 문서 밖에선 공백(spaces
)은 절대 들여쓰기로써 사용되어지지 않으며, 위 예제들의 의도적으로 규칙을 어긴 것이다. (역자 주: 리눅스 커널 문서에 들어가서 코드를 보면 들여쓰기가 공백으로 되어 있으며 공백의 개수 역시 제대로 맞지 않는다.
)
코딩 스타일은 모두 가독성과 일반적으로 이용 가능한 도구들을 사용한 유지 보수력에 대한 것이다.
선호되는 단행의 길이 제한은 80 열
이다.
80 열
을 초과하는 것이 극도로 가독성을 증대 시키면서도 정보를 숨기지 않는 한, 80 열
이상의 구문은 분별하기 쉬운 덩어리로 부서져야 한다.
자손(descendants
)들은 항상 부모보다 대체로 짧아야 하며, 오른쪽에 위치해야 한다. 일반적으로 사용되는 양식은 자손들을 함수의 여는 소괄호(parenthesis
)에 맞춰 정렬하는 것이다.
이러한 규칙들은 긴 인자(arguments
) 목록의 함수 머리(function header
)에도 적용되어질 수 있다.
그러나, 절대 printk
메세지와 같이 사용자가 볼 수 있는 문자열(string
)을 부수지 마라. 이를 부수게 되면 grep
될 수 있는 능력이 차단되기 때문이다.
언제나 언급되는 C 양식의 또 다른 주제는 중괄호의 배치이다. 들여쓰기 크기와 달리, 이는 다른 것들을 뛰어 넘는 하나의 전략을 선택해야 할 기술적인 이유가 거의 없으나, 선호되는 방식은, 선지자인 Kernighan
과 Ritchie
가 우리에게 보여준 것과 같이,
여는 중괄호를 줄의 끝에, 닫는 중괄호를 줄의 시작에 놓는 것이다,
그리하여:
if (x is true) { we do y }
이는 모든 함수가 아닌 모든 구문 블록들 (if
, switch
, for
, while
, do
)에 적용된다. E.g.
:
switch (action) { case KOBJ_ADD: return "add"; case KOBJ_REMOVE: return "remove"; case KOBJ_CHANGE: return "change"; default: return NULL; }
그러나, 여기에는 명명된 함수라는 특별한 경우가 있다: 그들은 여는 중괄호를 다음 줄의 시작에 가진다, 따라서:
int function(int x) { body of function }
전 세계의 이교도인(heretic people
)들이 이는 일관성 없다고 불평하는데... 글쎄... 일관성은 없지만, 모든 정상적인 생각을 하는 사람들은 (a)
K&R
이 정상(right
)이라는 것과 (b)
K&R
이 옳다(right
)는 것을 알고 있다. 그 밖에도, 어쨌든 함수는 특별하다 (너는 이들을 C
에서 중첩할 수 없다).
그 뒤에 동일한 구문이 계속되는 경우를 제외하면, 닫는 중괄호는 그 행이 비어있음에 주목하라.
예를 들어 do-문
의 while
혹은 if-문
의 else, 이것처럼:
do { body of do-loop } while (condition);
그리고
if (x == y) { .. } else if (x > y) { ... } else { .... }
근거: K&R
또한, 이러한 중괄호 배치는 가독성의 손실없이 비어있는(혹은 거의 빈) 행의 수를 최소화한다는 것에 주목하라. 따라서, 너의 화면에 새로운 행을 무한히 공급할 수 없으므로, 너는 주석을 달 수 있는 비어있는 행을 더 많은 가진다.
단행으로 충분한 곳에 중괄호를 불필요하게 사용하지 마라:
if (condition) action();
그리고
if (condition) do_this(); else do_that();
만일 오직 조건문의 하나의 분기가 단일 구문이라면 이는 적용되지 않는다; 후자의 경우 두 분기 모두 중괄호를 사용한다:
if (condition) { do_this(); do_that(); } else { otherwise(); }
또한, 반복이 하나의 단순한 단일 구문 이상을 포함한다면 중괄호를 사용하라:
while (condition) { if (test) { do_something(); }
공백을 사용하는 리눅스 커널 양식은 함수-대-키워드(function-versus-keyword
) 사용에 달려있다. (대부분의) 키워드 이후에 공백을 사용하라. 주목할만한 예외는 약간 함수를 닮은 (그리고 리눅스에선 일반적으로 소괄호와 함께 사용되지만 다음과 같이 언어 차원에서 소괄호를 필요로 하진 않는: sizeof info
뒤에 struct fileinfo info;
가 선언되어 있다.) sizeof
, typeof
, alignof
, 그리고 __attribute__
이다.
따라서 이러한 키워드 뒤에는 공백이 필요하다:
if
,switch
,case
,for
,do
,while
그러나 sizeof
, typeof
, alignof
, 혹은 __attribute__
은 그렇지 않다. E.g.
,
s = sizeof(struct file)
괄호쳐진 표현식의 주변(안)에 공백을 추가하지 마라. 이 예는 나쁘다:
s = sizeof( struct file );
포인터 자료형 혹은 포인터 자료형을 반환하는 함수를 선언할 때, 선호되는 *
의 사용은 자료형의 이름 혹은 함수의 이름에는 이웃하게, 자료형의 이름에는 이웃하지 않게 하는 것이다. 예:
char *linux_banner; unsigned long long memparse(char *ptr, char **retptr); char *match_strdup(substring_t *s);
대부분의 이항(binary
) 혹은 삼항(ternary
) 연산자 주변에는(양측에) 하나의 공백을 사용해라, 예를 들어 다음 중 어떤 것이든:
= + - < > * / % | & ^ <= >= == != ? :
그러나 단항(unary
) 연산자 앞에는 어떠한 공백도 사용하지 마라:
& * + - ~ ! sizeof typeof alignof __attribute__ defined
후위 증가 & 감소 단항 연산자 앞에는 공백이 필요없다:
++ --
전위 증가 & 감소 단항 연산자 뒤에는 공백이 필요없다:
++ --
그리고 .
과 ->
구조체 멤버 연산자 주변에는 공백이 필요없다.
행의 끝에 잇따르는 공백(trailing whhitespace
)을 남기지 마라. smart
들여쓰기를 쓰는 일부 편집기는 행의 시작에 적절하게 공백을 삽입할 것이다, 따라서 너는 코드의 다음 행에서 바로 입력을 시작할 수 있다. 그러나, 일부 특정 편집기들은 만일 네가 그 행에 코드를 입력하지 않고 끝냈다면 공백을 지우지 않는다, 가령 만일 네가 비어있는 행을 남긴다면. 결과적으로, 너는 잇따르는 공백을 포함하는 행들로 마치게 된다.
Git
은 너의 잇따르는 공백이 끼워넣어진 패치에 대해 경고할 것이고, 너를 위해 Git
은 선택적으로 잇따르는 공백을 벗길 수 있다. 그러나, 이러한 일련의 패치를 적용한다면, 이는 코드의 문맥 행(context line
)을 변경하면서 이후의 패치에서 일련의 실패를 만들 수 있다.
[링크] https://www.kernel.org/doc/html/latest/process/coding-style.html
이게... 벨로그에 구독 같은 기능이 없어서 새 글이 올라오는걸 알기가 어렵네요 ㅎㅎ;;