코드 스타일

오늘은 코드 스타일에 대한 얘기를 할까합니다. 여러가지 스타일 중 항상 논란의 핵심에 있는 몇가지만 짚어볼까 합니다.

CRLF / LF

사실 CR, LF 논란은 지금 컴퓨터 시대에는 논쟁이 될 필요도 없는 항목입니다.


아주 오래전 타자기(type writer)를 사용하던 시절에 Line Feed를 해서 행을 바꾸면 종이만 올라가게 되므로, 인쇄 헤더를 다시 행의 처음으로 옮기는 역할을 하는 Carriage Return을 해줘야만 다음 행의 처음부터 글을 쓸 수 있는 시나리오였습니다.


개인용 컴퓨터(Personal Computer)가 활성화 되면서 OS는 몇가지 계열로 나누어지게 됩니다. 이 부분도 세세하게 다루면 한 권의 책이 되니까, 간단하게 나누어서 Microsoft, MacOS, Linux/Unix 계열로만 구분하겠습니다.


Microsoft는 텍스트 문서에서 새로운 행을 구분할 때 CR과 LF를 함께 사용했습니다. LF만 있을 경우에는 윈도우즈 기본 어플리케이션인 메모장에서 보시다시피 행바꿈이 안되고 특수문자로 표시가 되는 것을 알 수 있습니다. (물론 최근 문서편집 어플리케이션들은 알아서 잘 표시합니다)


Linux는 LF만 사용하여 새로운 행을 구분합니다. 반면에 MacOS는 지금은 LF를 사용하지만, 초창기에는 CR만 사용하여 새로운 행을 구분했습니다.


이렇게 각 OS 계열별로 제각기로 행구분을 하다보니 인코딩 못지 않게 항상 개발자를 괴롭혔던 이슈 중에 하나입니다. 다행히도 요즘에는 편집기 혹은 IDE들이 성능이 우수하여 알아서 잘 표시해줍니다.



참고로 git에서는 이 숙제를 풀기 위해서 다음과 같이 정리를 했습니다.

  1. git 저장소에 보관되는 자료는 모두 LF를 사용하는 것을 원칙으로 합니다.
  2. git 설정 항목 중 하나인 autocrlf라는 기능은 다음과 같이 설정할 수 있습니다.
    1. true : 저장소에서 파일을 가져올 때 자동으로 LF를 CRLF로 변환하고, 또한 커밋을 할 때는 반대로 CRLF를 LF로 변환합니다.
    2. input : 저장소에서 파일을 가져올 때는 별도로 변환하지 않고, 커밋할 때 CRLF가 있다면 LF로 변환합니다.
    3. false : 커밋할 때도, 가져올 때도 수정하지 않고 git가 CRLF에 관여하지 않습니다.

괄호

코드의 동작과는 전혀 무관하지만, 사람마다 취향 및 가독성이 다르기 때문에 괄호도 정말 많은 이슈가 있는 항목 중 하나입니다.

중괄호

중괄호의 가장 큰 논란 중의 하나인 옆에 붙이느냐, 밑에 붙이느냐가 있습니다.

if (isBar) {
    bar();
} else {
    foo();
}
if (isBar)
{
    bar();
}
else
{
    foo();
}

전자의 경우 괄호의 시작이 어디에 있는지 한눈에 안보인다는 단점이 있고, 후자의 경우는 코드가 길어진다는 단점이 있습니다.

소괄호

소괄호 이슈는 띄어쓰기가 가장 큰 이슈입니다.

if (isFoo(a, b))
if ( isFoo(a, b) )
if ( isFoo( a, b ))

위에서 언급한 것 외에도 더 많은 종류의 스타일이 있습니다.

포인터

포인터 변수를 표시하는 별표(*)의 위치에 대한 논쟁도 항상 있어 왔습니다.

int* ptr;
int *ptr;
int * ptr;

첫번째는 int pointer를 하나의 데이터 형으로 간주하는 스타일입니다.
두번째는 ptr이라는 변수의 특성이 포인터라고 간주하는 스타일입니다.
세번째는 중립적으로 포인터를 어느 쪽에도 붙이지 않는 스타일입니다.


각각 진영의 반론을 들어보면 재미있습니다.


첫번째의 경우 다음과 같은 상황을 보겠습니다.

int a, b;
int *a, *b;

C언어 특성에 같은 데이터 형이면 콤마(,)로 구분하여 한 행에 여러개의 변수를 선언할 수 있습니다.
이 때 포인터 변수를 여러 개를 선언하기 위해서는 각각의 변수에 별표를 붙여줘야 합니다. 그래서 두번째를 주장하는 그룹에서는 이 이유 때문에 변수에 붙여서 쓰는게 맞다고 주장합니다.


두번째의 경우 다음의 예를 보겠습니다.

int *a;
a++;
*a = 10;

변수의 선언 형태는 데이터 형과 변수 이름을 나열하도록 되어있습니다. 따라서 별표가 포함된 것이 변수 이름처럼 느껴질 수 있고, 하지만 실제 사용시에는 변수 이름만 사용하므로 혼란이 발생할 수 있다는 것이 첫번째를 주장하는 그룹의 반론입니다. 또한, 포인터 변수의 값을 가져올 때도 별표를 사용하기 때문에 이 또한 혼란을 가중한다고 주장합니다.

들여쓰기

이 스타일은 정말 오랬동안 스타일 논쟁의 최상위권에 있는 것으로 알고 있습니다. 가장 크게 분류되는 그룹은 탭과 공백으로 나누어집니다.


탭을 쓰는 그룹은 공백으로 하게 되면 코드 위에서 커서를 움직일 때 너무 많은 동작이 필요하기 때문에 불편하다는 주장을 펼칩니다. 가장 일반적인 공백 4칸으로 들여쓰기를 하게 되면 한번 들여쓰기에 대한 커서를 움직일 때마다 4번씩 움직여야한다는 것이죠.


공백을 쓰는 그룹은 다음 두가지에 대한 불편함을 호소합니다.


우선 포맷팅이 전혀 안되는 편집기에서 탭은 8칸의 공백으로 표시됩니다. 따라서 들여쓰기를 4단계까지만 하더라도 32칸의 공백이 들여쓰기로 차지해버려서 가로의 길이가 80컬럼인 터미널의 경우 소스의 가독성이 너무 떨어진다는 점이 있습니다.


또한 보통 탭의 공백표시를 제어해주는 편집기를 사용해서 포맷을 맞춘 구문의 경우 -- 특히 ascii로 그리는 간단한 그림이나 표 같은 경우 -- 다른 곳에서 볼 경우에 똑같이 표시되지 않을 수 있다는 점도 있습니다.

AStyle

Astyle(링크)이라는 도구를 사용하면 손쉽게 코드 스타일을 정리할 수 있습니다. 자세한 설명은 여기를 참고하시면 됩니다.

참고로 저는 다음과 같은 옵션으로 사용합니다.

astyle -s4 -k2 -j -f -p -U -H -A1 -z2 *.c