C에 관한 coding convention을 찾다가 만족스러운 guide를 발견하여 영어 공부도 할겸 변역하고자 합니다. 이 글의 원본은 이곳 임을 밝힙니다. 번역을 허락해주신 Eno Thereska께 감사드립니다.

아직 영어를 배워나가는 단계이므로 혹여나 이해가 안가는 부분에 대해서는 메일을 주시면 제가 이해한 수준에서 최대한 도움을 드리도록 하겠습니다.

혹여나 오역 등에 대한 문의는 nohyg90@gmail.com 으로 주시면 검토 후 수정하겠습니다. 감사합니다.

혹시 이 글이 도움이 되었다면, 많은 분들이 볼 수 있게 이 글의 링크를 널리널리 공유해주시길 바랍니다!



history

160511 번역시작.



목차

1. 이름

이름에 단위를 포함하라
구조체의 이름
C 파일 확장자
올바른 이름 짓기
스택에 오르는 변수 이름
포인터 변수
전역 상수
Enum 이름
#define과 매크로 이름

2.포맷팅(formatting)

{} 규칙
키워드와 함수에 관한 () 규칙
한 줄은 78 캐릭터를 넘어서는 안된다.
if then else 포맷팅
switch 포맷팅
goto, continue, break, ? :의 사용
한 줄에는 하나의 실행문만

3. 문서화

코멘트는 이야기여야 한다.
문서 결정
헤더들을 사용하라
Gotchas(@)를 명확히하라
함수 선언 코멘트하라
실행문 문서화를 포함하라

4. 복잡함 관리

레이어링(Layering)

5. 기타 여러가지

헤더 파일 가드를 사용하라
C와 C++ 혼합
모든 변수를 초기화하라
Const를 올바르게 하라
짧은 함수들
매직 넘버들을 사용하지 마라(No magic numbers)
Error Return Check Policy
Enum을 사용 혹은 사용하지 않기 위하여
매크로들
Do Not Default If Test to Non-Zero
일반적으로, 함축된 할당을 피하라
큰 코드 블럭 바깥에 코멘팅하기
#ifdef 대신 #if를 사용하라
여러가지들
헤더파일 안에 데이터를 정의하지마라


1. 이름



적합한 이름 짓기

이름은 프로그래밍의 심장이다. 과거에 사람들은 어떤 사람의 진짜 이름을 아는 것은 자신에게 그 사람을 뛰어넘는 신비로운 힘을 준다고 믿었다. 만약 당신이 무언가의 진짜 이름을 생각해낼 수 있다면, 당신은 당신 자신, 그리고 후에 오는 사람들에게 그 코드를 뛰어넘는 힘을 줄 것이다. 우스갯소리가 아니다!

이름은 그것이 살고 있는 환경에 대한 깊은 생각 후에 나오는 과정의 결과물이다. 그 시스템을 전체로서 이해하는 프로그래머만이 그 시스템에 가장 “적합한” 이름을 만들 수 있다. 만약 그 이름이 자연스럽게 모든 것과 적절히 맞아떨어진다면, 관계가 명확해지고, 의미가 추론될 수 있고, 그리고 인간의 직관으로부터 오는 추리들이 기대했던 것처럼 잘 맞아떨어질 것이다.

만약 당신의 모든 이름이 Thing and Dolt가 될 수 있다는 것을 발견한다면, 당신은 아마 당신의 설계를 다시 보아야만 할 것이다.


함수 이름

  • 보통 모든 함수는 하나의 액션을 수행한다. 그래서 그 이름은 그것이 하는 일을 명확하게 보여주어야 한다:

    • error_check() 대신에 check_for_errors()를 data_file() 대신에 dump_data_to_file() 등을 사용하라. 이것은 함수와 데이터 객체(object)를 더욱 쉽게 구별 가능하도록 할 것이다.

    • Struct들은 보통 명사다. 함수 이름을 동사로 만들거나, 다른 naming convention을 따름으로써, 더욱 자연스럽게 읽혀지도록 할 수 있다.

  • 접미사는 때때로 유용하다:

    • max - 무언가가 가질 수 있는 최대값
    • cnt - 현재 진행 중인 count 변수의 현재의 값
    • key - 키 값

    • 예를 들어, retry_max 는 retries의 최대값을 의미하고, retry_cnt는 현재 retry count를 의미한다.
  • 접두사는 때때로 유용하다:

    • is - 무언가에 대한 질문 요청. 누군가가 is를 볼 때마다 그들은 그것이 질문이라는 것을 알 게 된다.
    • get - 값을 얻음
    • set - 값을 정함

    • 예를 들어, is_hit_retry_limit

이름에 단위를 포함하라

만약 변수가 시간, 무게, 혹은 다른 단위들을 나타낸다면, 단위를 이름안에 포함하라. 그러면 개발자들이 더욱 쉽게 문제들을 발견할 수 있을 것이다. 예를 들어:

uint32 time_outmsecs;
uint32 my_weight_lbs;

구조체의 이름

  • 이름 구성요소들을 분리하기 위해 언더바(_)를 사용하라
  • 구조체 내에서 변수들을 선언할 때, 메모리 낭비를 최소화를 시도하는 방식을 사용함으로써(because of compiler alignment issues), 혹은 사이즈, 알파벳 순으로써 선언하라. 예를 들어 “int a; char *b; int c; char *d;” 등은 사용하지 마라. “int a; int b; char *c; char *d;” 등을 사용하라. 비록 비트(bit) 영역에서 (그것이 하나의 bit 영역의 부분임을 분명히 하기위해) 예외가 발생할 수는 있지만, 각각의 변수들은 그들 소유의 타입과 라인을 가진다. 일반적인 bit 영역의 사용은 discouraged 됨을 주목하라. 만약 (구조체가) 여러 소스파일들에서 사용된다면, 주요 구조체들은 그들이 사용되는 파일, 혹은 분리된 헤더 파일의 최상단에 선언되어야 한다. 만약 그들(구조체)이 헤더 파일에 선언되었다면 구조체의 사용은 분리된 선언들에 의해야만, 그리고 “외부에” 있어야만 한다. 각각 멤버들 이름에 대해 의미 있는 접두사를 사용하는 것은 유용하다. 예를 들어, “struct softc”에 대해, 접두사는 “sc_“여야 한다.

예시

struct foo {
	struct foo *next; /* List of active foo */
	struct mumble amumble; /* Comment for mumble */
	int bar;
	unsigned int baz:1, /* BitField; line up entries if desired */
			fuz:5,
			zap:2;
	uint8_t flag;
};
struct foo *foohead; /* Head of global foo list */

스택에 있는 변수의 이름

  • 모두 소문자들로 사용하라
  • 단어 구분을 위해 ‘_‘를 사용하라

정당화

  • 코드 내의 변수 범위에 대한 접근이 명확하다.
  • 코드 내에서 모든 변수들이 다르게 보이고 인식할 수 있다.

예시

int handle_error (int error_number) {
	int error= OsErr();
	Time time_of_error;
	ErrorProcessor error_processor;
}

포인터 변수

  • *를 포인터 타입이 아닌, 변수 이름에 가까이 붙여라.

예시

char *name= NULL;
char *name, address;

전역 변수

  • 전역변수는 이름 앞에 ‘g_‘가 붙어야 한다.

  • 전역변수는 가능한 사용을 피해야 한다.

정당화

  • 변수의 범위를 아는 것은 중요하다.

예시

Logger g_log;
Logger* g_plog;

전역 상수

  • 전역 상수는 모두 대문자여야하고, ‘_‘를 구분자로 사용하여야 한다.

정당화

이렇게 사용하는 것이 전통적인 방식이다. 다른 #defineenum 라벨들과 충돌하지 않기 위해 주의해야한다.

예시

const int A_GLOBAL_CONSTANT= 5;

#define과 매크로들의 이름

  • #define과 매크로들을 ‘_‘를 구분자로 사용하여 모두 대문자로 만들라. 매크로들은 대문자화되어야 하고, 괄호로 싸여야하고, 부작용을 피해야만 한다. 매크로 이름의 앞과 뒤에 공간을 주는 것은 어떠한 공간이어도 된다. (즉 탭이나 띄어쓰기 등 아무거나 해도 된다는 말인듯 합니다.) 그러나 파일 내에서 TAB의 사용은 일관성을 가져야한다. 만약 그들이 한 줄로 늘어선 함수의 확장이라면, 그 함수는 모두 소문자로 정의되어야하고, 매크로는 모두 대문자로 된 같은 이름을 가져야한다. 만약 매크로가 하나의 표현이라면, 괄호로 그 표현을 감싸라. 만약 매크로가 하나 이상의 명령문이라면, 뒤따라오는 세미콜론이 동작하기 위해 “do {…} while(0)”을 사용하라. 백슬래쉬들을 우측으로 당겨라; 그것은 더 쉽게 읽을수 있도록 해줄 것이다.

정당화

이는 변경될 수 없는 값이나, 매크로 내에 있는 값을 명확히 해주고, 케어를 요하는 당신이 사용중인 construct를 명확히 해준다.

매크로 이름이나 enum 라벨이 같은 이름으로 사용된다면, 몇몇 눈에 잘 안띄는 흐릿한 에러들이 발생할 수 있다.

예시

#define MAX(a,b) blah
#define IS_ERR(err) blah
#define MACRO(v, w, x, y)
do {																\
	v = (x) + (y);										\
	w = (y) + 2;											\
} while (0)													\

Enum 이름

라벨들은 구분자로 ‘_‘를 사용하고, 모두 대문자로 쓰여야한다.

이것은 enum 라벨들의 표준 규칙이다. 마지막 원소에는 콤마가 없다.

예시

enum PinStateType {
	PIN_OFF,
	PIN_ON
};

에러 상태에 대한 라벨을 만들어라

어떠한 가능한 상태에도 enum이 없다는 것을 말할 수 있는 것은 자주 유용하다. 초기화 되지 않은, 혹은 에러 상태에 관한 라벨을 만들어라. 그리고 가능하다면 그것을 첫 라벨로 하라.

예시

enum { STATE_ERR, STATE_OPEN, STATE_RUNNING, STATE_DYING};


2. 포멧팅(formatting)



괄호의 위치

세 개의 주요 괄호들의 위치에 관한 전략들 중 권장되는 것은 다음이다:

	if (condition) {
		...
	}
	while (condition) {
		...
	}

언제 괄호가 필요한가

모든 if, while 그리고 do 문은 반드시 괄호를 가지거나, 혹은 하나의 라인으로 구성되어야 한다.

항상 괄호를 사용하는 형식

모든 if, while 그리고 do 문은 괄호 안에 하나의 실행문만이 있더라도 괄호를 요구한다. 예를 들어:

if (1 == somevalue) {
	somevalue = 2;
}

정당화

이것은 누군가가 후에 코드에 라인을 추가할 때, 그곳에 이미 괄호가 있다면, 그들이 괄호를 까먹지 않을 것임을 보장해준다. 이것은 더욱 일관된 모습을 제공한다. 이것은 실행 속도에 영향을 미치지 않는다. 괄호는 어렵지 않은 일이다.

한 라인의 형식

if (1 == somevalue) somevalue = 2;

정당화

이것은 밀집된 읽을 수 있는 폼을 유지하며 새로운 라인이 추가될 때 안전성을 제공한다.


닫히는 괄호에 코멘트를 달아라

닫히는 괄호에 코멘트를 다는 것은 당신이 코드를 읽을 때 도와준다. 왜냐하면 당신은 그것이 어떻게 흘러가는지 알기 위해 시작 괄호를 찾을 필요가 없기 때문이다.

while(1) {
	if (valid) {

	} /* if valid */
	else {
	} /* not valid */
} /* end forever */

화면 크기 제한을 생각하라

어떤 사람들은 코드를 일반적인 화면 크기내로 맞추기 위한 블럭들을 좋아한다. 그러면 코드를 읽을 때 스크롤을 할 필요가 없다.


키워드와 함수에 쓰이는 괄호 () 규칙

  • 키워드 바로 옆에 괄호를 쓰지마라. 사이에 공간을 둬라.

  • 함수 이름 바로 옆에 괄호를 써라.

  • 꼭 필요한 경우가 아니면 return 문에 괄호를 쓰지마라.

정당화

  • 키워드는 함수가 아니다. 키워드 바로 옆에 괄호를 두는 것은 함수와 키워드의 이름을 비슷해 보이게 만든다.

예시

if (condition) {
}

while (condition) {

strcpy(s, s1);

return 1;

한 라인은 78 character를 넘어서는 안된다.

  • 라인들은 78 character를 넘어서는 안된다.

정당화

  • 큰 모니터에 우리가 창을 넓게 펼지라도, 우리의 프린터는 프린트 가능한 너비만 프린트한다. 그러면 우리는 여전히 프린트할 코드가 필요하다.

  • 창이 더 커질 수록 우리는 더 적은 창을 가지게 된다. 더 많은 창을 켜는 것이 큰 창을 켜는 것보다 낫다.

  • 우리는 모든 터미널과 프린터에서 다른 결과물을 훨씬 올바르게 볼 수 있다.


if then else 포멧팅

레이아웃(Layout)

프로그래머에게 달려있다. 다른 괄호 스타일은 약간 다른 모습을 가져올 것이다. 하나의 흔한 접근은 이것이다:

if (condition) {
} else if (condition) {
} else {
}

만약 당신이 else if문을 사용한다면, 다루지 않는 경우들을 발견하기 위한 else블록을 항상 만드는 것은 좋은 생각이다. 그곳에서 적절한 액션을 취하지 않더라도, else문 안에 log 메시지를 넣는 것이 좋다.

조건 포멧

항상 비교문 안의 왼쪽에 상수를 넣어라. 예를 들어:

if (6 == errorNum) ...

이에 대한 첫 번째 이유로 만약 당신이 = 들 중 하나를 빠트린다면, 컴파일러는 당신에게 에러를 찾아줄 것이다. 두 번째 이유로, 이것은 당신이 찾고 있는 값을 표현식의 가장 끝에 두는 것 대신에, 당신이 바로 찾을 수 있도록 바로 오른쪽 앞에 둔다. 이 포멧에 익숙해지는 것은 약간의 시간이 걸리지만, 이것은 정말 유용하다.


switch 포멧팅

  • case 문을 통해 다음 case문으로 떨어지는 것은 코멘트가 포함되어 있는 경우에 한해서 허용된다.

  • default case는 항상 존재해야하고, 만약 그것에 다다라서는 안되는 경우인데 도달한다면 에러를 발생시켜야한다.

  • 만약 변수를 만들어야한다면, 모든 코드를 블록 안에 둬라.

예시

switch (...)
{
	case 1:
		...
	/* comments */

	case 2:
	{
		int v;
		...
	}
	break;

	default:
}

goto, continue, break 그리고 ?:문의 사용

Goto

Goto문은 구조를 잘 갖춰진 코드 내에서 아껴서 사용해야한다. goto에 대한 논의는 지루하므로 우리는 여기서 그것들에 대해 언급하지 않을 것이다. 그들이 유용하게 사용될 수 있는 주요 장소는 여러 레벨의 switch, for 그리고 중첩 while문을 중단할 경우이다. 비록 그런 일들을 하기 위한 요구는 내부 생성자들이 성공, 실패의 return 코드와 함께 반드시 분리된 함수들로 부서져야한다는 것을 가리킬 수 있을 지라도 말이다.

	for (...) {
		while (...) {
			...
			if (disaster) {
				goto error;
			}
		}
	}
	...
error:
	clean up the mess

goto문이 필수적일 때, 수행되는 라벨은 한 라인에 홀로 있어야만 하고, 잇따르는 코드의 좌측에 있어야한다. goto는 (가능하면 블록 헤더에) 그것의 유용성과 목적에 대해 코멘트 되어야 한다.

continue와 break

실제로 continue와 break는 goto를 가장한 것이므로 이곳에서 다루기로 한다.

goto 같은 continue와 break는 코드 안에서 magic이므로, 아껴서 사용되어야 한다. 간단한 마법을 가진 신내림을 받은 독자는 기록되지 않은 이유들이 어디에 있는지 안다.

주된 continue의 두가지 문제들:

  • 테스트 조건을 그냥 통과할 지도 모른다.

  • 증가, 증감 표현식을 그냥 통과할 지도 모른다.

두 가지 문제가 발생하는 다음의 예를 생각해보자:

while (TRUE) {
	...
	/* A lot of code */
	...

	if (/* some condition */) {
		continue;
	}
	...
	/* A lot of code */
	...
	if ( i++ > STOP_VALUE ) break;
}

주목하라: “A lot of code”는 프로그래머가 쉽사리 그 문제를 잡아내지 못하게 하기 위해 필요하다.

위의 예로부터, 한층 더 규칙들이 주어질 수 있다: continue와 break를 같은 loop안에서 섞는 것은 재앙으로 가는 명백한 길이다.

?:

보통 사람들이 ?: 사이에 너무 많은 코드를 시도하려 하고 또, 채워넣는 것이 문제이다. 여기에는 몇 개의 명백한 규칙들이 있다:

  • 다른 코드로부터 그것을 실행하도록 괄호 안에 condition을 두어라.

  • 가능하다면 테스트를 위한 액션은 간단한 함수여야한다.

  • 한 라인에 둘 정도로 명백하지 않다면, then과 else 문을 위한 액션은 분리된 라인에 두어라.

예시

(condition) ? funct1() : funct2();

or

(condition)
	? long statement
	: another long statement;

한 라인에 하나의 실행문

실행문들이 매우 밀접하게 연관이 있지 않는 한, 한 라인에는 하나의 실행문 만이 있어야 한다.

이유는 이렇다:

  1. 읽기가 쉽다. 약간의 여백 역시 사용하라. 한 라인의 코드를 읽는 것보다 더 좋은 것은 없다.

한 줄에 하나의 변수

이것과 연관되는 것은 항상 한 줄에 하나의 변수를 정의하라는 것이다:

Not:

char **a, *x;

Do:

char **a = 0; /* add doc */
char *x = 0; /* add doc */

이유는 이렇다:

  1. 문서화는 한 줄에 있는 변수에 대해서 추가될 수 있다.

  2. 변수들이 초기화되는 것은 명백하다.

  3. 변수 선언이 clear하다. 그것은 당신이 char형 선언만을 의도했을 때, 포인터를 선언해버리는 가능성을 줄여준다.


Enums를 사용하기 위한, 혹은 사용하지 않기 위한

C는 상수 변수를 허락한다. 상수로서 enums의 사용하는 것을 비난하여야만 한다. 불행히도 대부분의 컴파일러들에서 상수는 공간을 차지한다. 몇몇 컴파일러는 상수를 제거할 것이지만 모두 그렇지는 않다. 공간을 차지하는 상수들은 임베디드 시스템 같은 빡빡한 메모리 환경에서 그들이 사용되는 것을 방해한다. workstation 유저들은 상수를 사용해야만 하므로, 이 남은 토론을 무시해야한다.

enums로서 #define이 선호되는 일반적인 enums들은 디버거에 의해 이해된다.

enums는 보증하는 크기가 아니라는 것을 알아라. 그러니 당신이 알려진 변수 범위를 사용할 수 있는 타입을 가진다면 그리고 그것을 메시지로 옮긴다면, 당신은 enum을 타입으로서 사용할 수 없다. 올바른 정수 크기를 사용하고 상수나 #define을 사용하라. 그 enum안에 없는 값을 형변환 함으로서, 정수와 enum 사이에서의 형변환은 에러를 발생할 경향이 매우 크다.


헤더 파일 가드를 사용하라

포함하는 파일들은 그 파일들을 가드하는 매크로의 사용을 통한 여러 포함에 대해 보호되어야 한다. c++의 적합성, 상호 연산성의 이유에 대해 주목하고, 헤더 가드의 첫번째나 마지막 문자로서 언더스코어 ‘_‘를 사용하지마라. (아래를 보아라)

#ifndef sys_socket_h
	#define sys_socket_h /* NOT _sys_socket_h_ */
	#endif

매크로들

C를 Pascal로 바꾸지마라

매크로 치환을 통해 문법을 변경하지마라. 그것은 프로그램을 지능적이지 못하게 만들 것이다.

매크로들을 인라인 함수(inline function)으로 대체하라

C에서 매크로들은 코드 효율성에 대해서 필요하지 않다. 인라인(inline)을 사용하라. 하지만 짧은 함수들에 대해서는 매크로도 괜찮다.

예시

#define MAX(x, y)	((x) > (y) ? (x) : (y)) // Get the maximum

위의 매크로는 정수들에 대해 효율성을 잃지 않고 아래의 인라인 함수(inline function)으로 대체될 수 있다:

inline int
max(int x, int y) {
	return (x > y ? x : y);
}

부작용에 주의하라

매크로들은 주의를 기울여 사용되어야한다. 왜냐하면 부작용을 가지고 있는 표현식과 함께 호출될 때 에러에 대한 가능성이 있기 때문이다.

예시

Max(f(x), z++);

항상 표현식을 괄호로 감싸라

표현식을 매크로에 넣을 때, 연산 교환법칙의 모호성을 피하기 위해 항상 그 표현식을 괄호로 감싸라.

예시

#define ADD(x, y)	x + y

같은 것은 반드시

#define ADD(x, y)	((x) + (y))

처럼 쓰여야 한다.

유일한 매크로 이름을 만들어라

전역 변수들처럼 매크로도 다른 패키지의 매크로들과 충돌을 일으킬 수 있다.

  1. 매크로 이름 앞에 패키지 이름을 붙여라.
  2. MAX, MIN 등과 같은 흔하고 단순한 이름을 피하라.

모든 변수들을 초기화하라

  • 항상 모든 변수를 초기화하라. 항상. gcc에 flag -W를 함께 사용하는 것은 초기화 되지 않은 변수들에 대한 연산을 잡을 수 있다. 그러나 그것은 또한 아닐 수도 있다.

정당화

  • 포인터나 초기화 되지 않고 남아있는 변수들에 대해 당신이 믿을 수 있는 것보다 더 많은 문제들이 언젠가는 발견될 것이다.

짧은 함수들

  • 함수들은 한 페이지 내로 그들 자신을 제한해야한다.

정당화

  • 각각의 메소드는 하나의 목표만을 달성하기 위한 기술을 나타낸다는 것이 그 아이디어이다.

  • 오랫동안 돌릴 때(in the long run) 많은 비효율성의 인자들은 틀렸다는 것이 밝혀졌다.

  • True 함수 콜은 하지 않는 것보다 느리다. 하지만 충분히 생각한 결정이 필요하다 (너무 이른 최적화를 보라).


Null 실행문들을 기록하라

항상 for 또는 while 실행문에 관한 null body를 기록하라. 그 null body가 의도적이고, 결여된 코드가 아님을 명확히 하기 위해서 말이다.

while (*dest++ = *src++)
{
	;
}

non-zero에 대한 테스트라면 default 하지마라

non-zero에 대한 테스트를 default 하지 마라., 즉

if (FAIL != f())

가 아무리 FAIL이 C에서는 false로 고려되는 0의 값을 가질 지라도,

if (f())

보다 낫다. 명백한 테스트는 나중에 누군가가 실패 리턴이 0 대신에 -1이어야만 하는 것을 정할 때 당신을 도와줄 것이다. 명백한 비교는 비교값이 절대 바뀌지 않는 경우에만 사용되어야 한다; 예를 들어, if (!(bufsize % sizeof(int)))는 그 테스트의 (boolean이 아닌) 숫자의 본질을 반영하기 위해 if ((bufsize % sizeof(int)) == 0)로 대신 쓰여야만 한다. 문제를 일으키는 잦은 지점은 그 결과가 절대 한번도 default가 되지 않는 곳에서 문자열이 같은 지 테스트하기 위해 strcmp를 사용하는 중이다. 선호되는 접근은 STREQ라는 매크로를 정의하는 것이다.

#define STREQ(a, b)	(strcmp((a), (b)) == 0)

더 적절하게 표현하면, 인라인 메소드(inline method)를 사용하는 것이다:

inline bool
string_equal(char* a, char* b)
{
	(strcmp(a, b) == 0) ? return true : return false;
		Or more compactly:
	return (strcmp(a, b) == 0);
}

이것은 단지 하나의 예라는 것을 주목하라, 이 비교를 하기 위해서 당신은 사실 표준 라이브러리 문자열 형식을 사용해야만 한다.

아래의 제한들에 만족하는 술부나 다른 함수들 또는 표현식들에 대해서 그 non-zero 테스트는 자주 default된다:

  • 다른 어떤 것도 아닌, false를 위해 0을 return하는 경우

  • true return의 의미를 절대적으로 명백하게 하기 위해서 이름이 지어진 경우라면 check_valid()가 아닌, is_valid() 술부를 호출하라.


습관적으로 함축된 할당(Embedded assignments)을 피하라

함축된 할당을 위한 시간과 공간이 있다. 몇몇 구조들에서, 그 코드를 더 크고, 읽기 힘들게 만드는 것 없이, 그 결과를 달성하기 위한 더 나은 방법은 없다.

while (EOF != (c = getchar())) {
	process the character
}

++와 --연산자는 할당 실행문으로서 계산한다. 따라서 많은 목적들을 위해, 부작용을 가진 함수들을 사용하라. 런타임 성능을 향상시키기 위한 함축된 할당 실행문을 사용하는 것 또한 가능하다. 하지만, 함축된 할당문이 인공적인 공간에서 사용될 때 일어나는 증가되는 속도와 감소되는 유지가능성 사이의 거래(tradeoff)를 고려해야만 한다. 예를 들어,

a = b + c;
d = a + r;

d = (a = b + c) + r;

로 대체되어서는 안된다. 심지어 후자가 한 사이클을 더 절약할 수 있을지라도 말이다. 오랜 시간의 동작에서(In the long run) 이 둘 간의 시간 차이는 옵티마이저가 숙성(maturity) 되는 동안에 감소될 것이다. 반면에 유지의 용이함의 차이는 후자의 코드 조각들이 어떻게 흘러가는지에 대한 사람의 기억이 흐릿해지기 시작함으로서 증가할 것이다.



Yonggoo Noh

I am interested in Computer science and Mathematics.