엠스톤 bebop 에서 퍼옴
리눅스 커널 코딩 스타일
리누스 토발즈 작성
(Original english text is LinuxCodingStyle.)
이 짧은 문서는 리눅스 커널을 위한 코딩 스타일을 기술한 것입니다. 코딩 스타일은 very personal한 것이지만, 전 누구에게도 나의 view를 force 하고 싶지 않습니다.
하지만, 이것은 what goes for anything that I have to be able to maintain 이고, 전 다른 대부분의 것에도 이것을 더 좋아합니다.
Please at least consider the points made here.
우선, GNU coding standards 를 프린트한후 읽지 마십시오. Burn them, it's a great symbolic gesture.
Anyway, here goes:
들여쓰기
탭은 8 characters, 그리고 thus indentations 또한 8 characters 입니다. 4(또는 단지 2!) characters 들여쓰기를 하는 것은 PI의 값을 3으로 define하는 것과 유사한 얘깁니다.
Rationale: 들여쓰기에 숨겨진 모든 idea는 어디서 블록 제어를 시작하고 끝낼지를 명확히 정하기 위해서입니다.
특히 당신이 스크린을 20시간 연속으로 볼때, 당신이 large 들여쓰기를 한다면 들여쓰기의 작용으로 스크린을 보는것이 많이 쉬워지게 될것입니다.
Now, 8-character 들여쓰기가 코드를 너무 오른쪽으로 들어가게 해서 80-character terminal screen에서는 보기가 힘들다고 주장하는 사람들도 있습니다.
해답은 당신이 3 levels 이상의 들여쓰기을 할 필요가 있다면 당신이 잘못한 것이며 당신의 프로그램을 고쳐야 할 것입니다.
요약하자면, 8-char indents는 읽기 쉽게 해주며 당신이 함수들을 깊게 nesting 하는것을 경고해주는 장점도 있습니다. 그 경고를 조심하세요.
중괄호 치기
C Styling에서 언제나 논의에 오르는 또다른 문제는 중괄호 배치입니다. 들여쓰기 크기와는 달리, 하나의 중괄호 치는 방법을 선택해야할 이유는 별로 없지만,
선지자 Kernighan and Ritchie께서 우리에게 보여주셨던 더 좋은 방법은 여는 괄호를 줄 마지막에 놓고, 닫는 괄호는 맨 앞에 놓는 것이다.
if (x is true) {
we do y
}
그러나 함수의 경우에는 특별히 여는 중괄호가 다음행의 처음에 옵니다.
int function(int x)
{
body of function
}
전세계의 반대의 사람들은 claimed that this inconsistency is ... well ... inconsistent, 그러나 모든 right-thinking 사람들은
know that (a) K&R are right and (b) K&R are right. 그외에도 함수는 어쨋든 특별합니다.
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:
do {
body of do-loop
} while (condition);
and
if (x y) {
..
} else if (x > y) {
...
} else {
....
}
Rationale: K&R.
Also, 이러한 brace-placement는 readability는 그대로 유지하면서 empty line의 수를 최소화 시키기까지 합니다.
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.
Naming
C 는 엄격하고 간소한 언어이며, 당신이 이름지을때도 마찬가지여야 합니다. Modula-2나 Pascal 프로그래머들과는 달리,
C 프로그래머들은 ThisVariableIsATemporaryCounter 같은 cute names를 사용하지 않습니다. C 프로그래머는 그 변수를 "tmp"라고 더 쓰기 쉽게 이름 지을 것이며,
더 이해하기 어려운 이름은 사용하지 않을 것입니다.
하지만 , mixed-case names들은 나쁜것이지만, 전역변수에 있어서 서술적인 이름은 필수적인 것입니다. 전역변수를 "foo"라고 이름짓는 것은 shooting offense입니다.
GLOBAL 변수들은 (오직 _really_ 필요할 때만 쓰라) 서술적인 이름을 가져야 하며, 그점은 전역 함수들도 마찬가지입니다.
당신이 active users의 수를 세는 함수를 가진다면 당신은 그것을 "count_active_users()"또는 비슷한 이름을 짓지, "cntusr()"같은 이름 으로 짓지는 않을 것입니다.
이름에 타입을 포함시키는것은(Hungarian notation라 불림) brain damaged입니다 - 컴파일러는 어쨋든 타입을 알고 있고 검사할 수 있으며,
그것은 프로그래머만 혼란시킵니다. M$가 버그투성의 프로그램을 만드는것은 당연합니다.
지역 변수의 이름은 짧아야 하며, 적절한 이름이어야 합니다. 만약 당신이 어떤 랜덤한 정수 루프 카운터를 가진다면, 그것은 "i"라고 불러질 것입니다.
그걸 "loop_counter"라고 부르는 것은 오해의 가능성은 없겠지만 비생산적입니다. Similarly, "tmp"도 임시적인 값을 저장해두는데 사용되는 어떤 타입의 변수 이름으로도 사용될수 있습니다.
지역 변수이름이 혼란스러워지는것이 두렵다면, 당신은 function-growth-hormone-imbalance syndrome 라 불리는 다른 문제를 안게 될것이다.
See next chapter.
Functions
함수는 short and sweet 하여야 하며, 한가지만을 해야 합니다. 함수는 하나 또는 두 화면에 가득찰 정도의 텍스트(the ISO/ANSI screen size is 80x24, as we all know) 여야 하며,
한가지를 잘 수행해야 합니다.
The maximum length of a function은 그 함수의 복잡도와 들여쓰기 level에 역비례 합니다.
So, 여러개의 case에서 여러가지의 작은 작업을 하는 단 하나의 긴 case-statement를 가진 함수의 경우, 더 길어도 괜찮습니다.
그러나, 만약 당신에게 복잡한 함수가 있고, less-than-gifted 고등학교 1학년 학생조차 그 함수가 무엇에 대한 것인지를 모를거라 의심이 든다면,
당신은 모든 면에서 면밀히 maximum limit에 충실해야 합니다.
설명적인 이름을 가진 거드는 함수를 사용하세요(만약 당신이 그것이 performance-critical 하고 당신이 한것보다 나아질수 있을 것 같다고 생각한다면,
컴파일러에게 그함수를 인라인으로 할수 있는지 요구할 수 있습니다).
함수의 다른 척도로 지역 변수의 갯수를 들수 있습니다. 지역 변수는 5-10을 초과하지 말아야 하며, 초과한다면 당신은 뭔가 잘못하고 있는것입니다.
다시 생각해보면, 함수는 더 작은 조각으로 쪼갤 수 있습니다. 인간의 두뇌는 일반적으로 7개의 다른 것에 관한 track을 유지하고 있으며,
anyting more and it gets confused. You know you're brilliant, but maybe you'd like to understand what you did 2 weeks from now.
Commenting
주석은 좋은것이지만, 또한 over-commenting의 위험도 가지고 있습니다.
절대 주석으로 당신의 코드가 어떻게 동작하는지 설명하지 마세요
: 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, 주석으로 코드가 어떻게 움직이는지가 아니라, 뭘 하는지를 말하고 싶어하세요. 또한, 함수 몸체 내부에 주석을 다는걸 피하도록 하세요
: 함수가 너무 복잡해서 개별적으로 주석을 달아야 할 필요가 있을때, 당신은 아마 잠시 챕터 4로 되돌아가게 될것입니다.
당신은 어떤부분에 something particularly clever(or ugly) 대한 것을 주의나 경고를 하기위한 작은 주석을 달 수 있지만 너무 많이 하지는 말도록 하세요.
대신에 함수의 첫부분에 주석을 달아서, 함수가 무엇을 하고, 함수가 왜 그렇게밖에 못했는지를 말하세요.
실수
That's OK. 우리 모두는 실수를 합니다. 당신은 아마 오랜동안 유닉스 유저의 보조자였던 "GNU emacs"가 당신을 위해 자동으로 생성한 formats C sources에 의한 것이었다고 말하고,
그렇다고 인정하지만, 디폴트로 사용된 값은 원하는 것에 미치지 못합니다 (사실, 그것은 random typing보다 못합니다 - GNU emacs에서의 무한한 타이핑은 절대 좋은 프로그램을 만들어 내지 못할겁니다).
So, 당신은 GNU emacs를 집어치우든지, 아님 그것을 더나은 값으로 바꿀수 있습니다. 후자를 하기위해, 밑의 것들을 당신의 .emacs 파일에 붙일수 있습니다.
(defun linux-c-mode ()
"C mode with adjusted defaults for use with the Linux kernel."
(interactive)
(c-mode)
(c-set-style "K&R")
(setq c-basic-offset 8))
이것은 the M-x linux-c-mode command를 정의 할 것입니다. -*- linux-c -*- 를 처음 두 라인에 추가한다면, 당신이 모듈을 hacking할 때 이 모드가 자동으로 발동될 것입니다.
또한, 당신이 /usr/src/linux 에 있는 소스 파일들을 편집할때, 자동으로 linux-c-mode``로 변하기를 원한다면 ``.emacs 파일에 다음을 추가하기를 원할겁니다.
(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode)
auto-mode-alist))
그러나 당신이 emacs로 올바른 formatting을 하는데 실패하더라도, 모든것을 잃는게 아닙니다: "indent"를 사용하세요.
자, 다시, GNU indent는 GNU emacs를 쓰기위해 당신이 몇가지 command line options가 필요한 이유같은 brain dead settings 을 가지고 있습니다.
그러나, 그렇게 나쁜것만은 아닙니다. makers of GNU indent조차 K&R의 권위를 인정해서(GNU 사람들이 나쁜것은 아니고, 단지, 이 일에서만 몇가지 잘못했을 뿐)
"-kr -i8"옵션("K&R, 8 character indents"를 뜻함)만 주면 되기 때문입니다.
"indent"는 많은 옵션을 가지고 있고, 특히 comment re-formatting을 할때 당신은 맨페이지가 보고싶어질 것입니다. 그러나 기억하세요
: "indent"가 나쁜 프로그래밍의 해결법은 아닙니다.
Configuration-files
configuration 옵션들(arch/xxx/config.in, and all the Config.in files)에 있어서, 다소 다른 들여쓰기가 사용됩니다.
코드에선 3 레벨의 들여쓰기가 사용되지만, config-option에 의한 텍스트는 should have an indention-level of 2 to indicate dependencies.
후자의 경우 오직 bool/tristate 옵션만 적용합니다. 다른 옵션에 있어선, common sense만 사용됩니다. 예:
if [ "$CONFIG_EXPERIMENTAL" "y" ]; then
tristate 'Apply nitroglycerine inside the keyboard (DANGEROUS)' CONFIG_BOOM
if [ "$CONFIG_BOOM" ! "n" ]; then
bool ' Output nice messages when you explode' CONFIG_CHEER
fi
fi
일반적으로, CONFIG_EXPERIMENTAL 은 안전성이 고려되지 않은 모든 옵션들을 감쌀것입니다. 쓸모없는 데이터로 알려진 모든 옵션들은 (DANGEROUS)로 나타내어질 것이고,
다른 Experimental 옵션들은 (EXPERIMENTAL)로 나타내어질 것입니다.
Data structures
안에서 생성되고 소멸되는 data structure가 단일 스레드 환경 외부에 visibility를 가진다면 그 data structure는 언제나 reference counts를 가져야 합니다.
커널 내부에선, garbage collection 이 존재하지 않으며 (그리고 커널 외부에선 garbage collection 이 느리고 비 효율적입니다),
그것은 당신이 모든 접근에 대하여 절대적으로 reference count를 해야한다는 것을 의미합니다.
Reference counting 은 당신이 locking을 피할 수 있고, 복수의 사용자가 그 자료구조에 병렬적으로 접근할 수 있게 해줍니다
- 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.
locking은 reference counting의 대체가 아님을 유념하세요. reference counting이 memory management technique이면,
Locking은 data structures를 coherent하게 유지하는것입니다.
다른 "classes"의 유저들이 존재할때, 많은 data structures는 실제로 두 레벨의 reference counting을 가질 수 있습니다.
The subclass count는 subclass users의 갯수이며, subclass count가 0이 되면 decrements the global count just once.
이런 "multi-reference-counting"의 예를 memory management("struct mm_struct": mm_users and mm_count)와
파일시스템 코드("struct super_block": s_count and s_active)에서 발견할 수 있습니다.
Remember: 다른 스레드가 당신의 data structure를 발견할 수 있고, 당신이 거기에 reference count를 두지 않았다면, you almost certainly have a bug.