"훌륭한 프로그래밍 스타일은 코드의 효과적인 구성에서 시작됩니다. 명확하고 일관된 방식으로 프로그램 구성 요소를 구성함으로써 프로그램을 더욱 효율적이고 읽기 쉽고 유지보수 가능하게 만들 수 있습니다."
이 문서는 소프트웨어 공학 연구소(SEL)에서 권장하는 C 프로그램 작성 스타일을 설명하며, 여기서 "훌륭한 스타일"로 작성된 코드는 다음과 같이 정의됩니다.
체계적임 (Organized)
읽기 쉬움 (Easy to read)
이해하기 쉬움 (Easy to understand)
유지보수 가능함 (Maintainable)
효율적임 (Efficient)
이 문서는 SEL 환경의 프로그래머를 위해 특별히 작성되었지만, 이러한 표준의 대부분은 일반적으로 모든 환경에 적용할 수 있습니다. 이 문서에서는 C에 대한 실무 지식이 있다고 가정하므로 C 프로그래밍 방법을 가르치려고 시도하지 않습니다. 대신, C 코드의 효율성을 향상시키는 좋은 사례를 지적하는 데 중점을 둡니다.
이 문서는 C 프로그램, 파일 및 함수 구성을 위한 지침을 제공합니다. 또한 변수, 구문 및 함수의 구조와 내용에 대해서도 설명합니다. 지침은 코드를 쉽게 읽고 이해하고 유지 관리할 수 있도록 작성하는 데 도움이 되도록 고안되었습니다.
소프트웨어 공학 원리가 논의되고 설명됩니다.
핵심 개념이 강조 표시됩니다.
코드 예제가 좋은 사례를 설명하기 위해 제공됩니다.
이 섹션은 C 코드의 가독성과 유지보수성을 최대화하는 일반적인 원칙들을 요약합니다.
캡슐화 및 정보 은닉 기법을 사용하여 프로그램을 구성하세요.
공백을 사용하여 코드의 가독성을 향상시키세요.
다른 사람들이 여러분의 프로그램을 이해할 수 있도록 주석을 추가하세요.
의미 있고 읽기 쉬운 이름을 만드세요.
가능하다면 ANSI C 표준을 따르세요.
캡슐화와 정보 은닉 기법은 더 잘 정리되고 유지보수가 쉬운 코드를 작성하는 데 도움이 될 수 있습니다. 캡슐화는 관련된 요소들을 그룹화하는 것을 의미합니다. 여러분은 여러 수준에서 캡슐화를 할 수 있습니다.
예를 들어:
하나의 아이디어를 중심으로 응집력 있는 구조를 만들기 위해 헤더 파일을 사용하여 프로그램 파일들을 구성하세요.
데이터 섹션과 함수 섹션으로 구성하세요.
논리적으로 관련된 그룹별로 함수를 구성하세요.
논리적 그룹(데이터 구조)별로 데이터를 구성하세요.
정보 은닉은 프로그램 요소의 가시성(또는 범위)을 제어하는 것을 의미합니다.
예를 들어 C 구조체를 사용하여 함수와 데이터의 범위를 제어할 수 있습니다.
헤더 파일에 관련된 파일만 포함하고, 필요한 파일만 포함하세요. 예를 들어 <time.h>는 시간을 조작하는 파일에서만 포함되어야 합니다.
현재 파일 외부에서 정의된 변수는 외부 변수라고 합니다. 외부 변수는 선언된 외부 파일 내에서만 볼 수 있으며, 개별 함수에서만 사용해야 합니다.
[그림 1은 정보 은닉 개념을 보여줍니다. 코드는 두 개의 파일, 세 개의 함수, 그리고 범위 내에 있는 여섯 개의 변수로 구성되어 있습니다. 각 줄의 오른쪽에는 변수가 나타나는 범위가 표시되어 있습니다.]
x.c
#include "local.h"
int a = 2; /* a */
static int b = 3; /* ab */
main() /* ab */
{
int c = a + b; /* abc */
xsub(c); /* abc */
xsub(d); /* ab */
int d; /* abd */
{
int e = 7 * d; /* abde */
ysub(e); /* abde */
}
ysub(e); /* abde */
}
y.c
#include "local.h"
ysub(f) /* f */
int f; /* f */
{
extern int a; /* af */
printf("%d\n", a + f); /* af */
}
실시간 시스템에서 성능 저하를 고려하면서도 읽고 유지 관리하기 쉬운 코드를 작성하세요(적절한 경우). 빈 줄, 공백, 들여쓰기 형태로 공백을 추가하면 코드의 가독성이 크게 향상됩니다.
코드 "단락" 사이의 빈 줄을 신중하게 사용하면 텍스트 시퀀스의 논리적 구조를 더욱 명확하게 만들어 가독성을 크게 향상시킬 수 있습니다. 코드나 주석에서 빈 줄을 사용하여 프로그램 라인을 의미 있는 덩어리로 나눌 수 있습니다. 다음 예는 코드 단락 나누기를 보여줍니다.
예: 코드 단락 나누기
#define LOWER 0
#define UPPER 300
#define STEP 20
main()
{
int fahr;
for (fahr = LOWER; fahr <= UPPER; fahr = fahr + STEP)
printf("%4d %6.1f\n", fahr, (5.0/9.0)*(fahr - 32));
}
코드 "단락" 사이의 빈 줄을 신중하게 사용하면 텍스트 시퀀스의 논리적 구조를 더욱 명확하게 만들어 가독성을 크게 향상시킬 수 있습니다. 코드나 주석에서 빈 줄을 사용하여 프로그램 라인을 의미 있는 덩어리로 나눌 수 있습니다. 다음 예는 코드 단락 나누기를 보여줍니다.
예: 코드 단락 나누기
#define LOWER 0
#define UPPER 300
#define STEP 20
main() /* 화씨-섭씨 변환표 */
{
int fahr;
for (fahr = LOWER; fahr <= UPPER; fahr = fahr + STEP)
printf("%4d %6.1f\n", fahr, (5.0/9.0)*(fahr - 32));
}
그러나 과도한 빈 줄 사용은 그룹화의 목적을 해치고 가독성을 떨어뜨릴 수 있습니다. 따라서 프로그램의 논리적 부분들을 분리하는 데 한 줄의 빈 줄만 사용하세요.
적절한 공백 사용은 개별적인 텍스트 요소의 가독성을 향상시키고 오류를 방지하는 데 도움이 됩니다. 다음 예는 연산자와 피연산자를 분리하기 위해 공백을 사용하는 방법을 보여줍니다. 첫 번째 예는 읽기 쉽지만, 두 번째 예는 읽기가 더 어렵고 오류를 유발할 수 있습니다. 두 번째 예에서 연산자 * 앞의 공백은 컴파일러에 의해 주석의 시작으로 해석됩니다. 쉼표 뒤에 공백을 하나 넣어 가독성을 향상시키세요. 아래 세 번째 예를 참고하세요.
예: 좋은 공백 사용
*average = total / count; /* 평균 계산 */
예: 나쁜 공백 사용
*average=*total/*count; /* 평균 계산 */
^ begin comment end comment^
예: 쉼표 공백 사용
concat(s1, s2)
들여쓰기를 사용하여 코드의 논리적 구조를 보여주세요. 연구에 따르면 4개의 공백이 가독성과 유지보수성을 위한 최적의 들여쓰기 크기입니다. 그러나 긴 변수 이름을 가진 고도로 중첩된 코드에서는 4개의 공백 들여쓰기가 코드 줄이 너무 길어져 읽기 어렵게 만들 수 있습니다. 이러한 경우에는 다른 방법이 없다면 4개의 공백보다 적은 들여쓰기를 사용하세요.
예: 4칸 들여쓰기
main()
{
int c;
c = getchar();
while (c != EOF) {
putchar(c);
c = getchar();
}
}
신중하게 작성된 주석은 코드를 읽는 사람이 단순히 코드를 읽는 것만으로는 알 수 없는 정보를 제공할 수 있습니다. 주석은 여러 수준에서 추가할 수 있습니다.
프로그램 수준에서는 프로그램의 전반적인 설명과 구성을 제공하는 README 파일을 포함할 수 있습니다.
파일 수준에서는 파일의 목적을 설명하고 다른 관련 정보(4장에서 더 자세히 설명)를 제공하는 파일 머리말(prolog)을 포함하는 것이 좋습니다.
함수 수준에서는 함수가 무엇을 하는지 설명하는 함수 머리말 주석을 작성하세요.
파일 전체에서 데이터가 선언되거나 정의되는 곳에서는 변수의 목적을 설명하는 주석을 추가하는 것이 유용합니다.
주석은 길이와 스타일에 따라 다양하게 작성될 수 있습니다. 코드를 읽는 사람이 이해하기 쉽도록 정보를 추가하고 중요한 부분을 강조하는 데 주석을 사용하세요. 프로그램 설계 언어(PDL)(소프트웨어에서 방법과 절차를 설계하고 문서화하는 방법)에 포함된 코드를 다시 설명하거나 반복하지 마세요.
이 섹션에서는 주석 사용법을 설명하고 예시를 제공합니다.
/******************************************************************************
* FILE NAME
*
* PURPOSE
*
*****************************************************************************/
/******************************************************************************/
예: 블록 주석
/*
* 주석 내용을 완전한 문장으로 작성하세요.
* 문장이 두 개 이상인 경우 블록 주석을 사용하세요.
*/
double ieee_r[]; /* IEEE 실수형 8바이트 값의 배열 */
unsigned char ibm_r[]; /* IBM 실수형 8바이트 값의 문자열 */
int count; /* 실수형 8바이트 값의 개수 */
탭 문자를 사용하여 코드 구문에서 주석을 충분히 분리하세요.
코드나 데이터 정의 블록에 둘 이상의 짧은 주석이 있는 경우, 모든 주석을 동일한 탭 위치에서 시작하고 동일한 위치에서 끝나도록 정렬하세요.
예: 인라인 주석
switch (ref_type)
{
/* RSL 루틴 c_calpvs를 사용하여 a/c 위치 또는 속도 벡터 요청을 수행합니다. */
case 1:
case 2:
...
case n:
}
일반적으로 짧은 주석을 사용하여 변수 정의를 설명하고, 블록 주석을 사용하여 계산 과정을 설명하세요.
예: 블록 주석 vs. 짧은 주석
권장되는 스타일:
/*
* 메인 시퀀스: 모든 사용자 요청을 획득하고 처리합니다.
*/
while (!finish()) {
inquire();
process();
}
while (!finish()) { /* 메인 시퀀스: */
inquire(); /* 사용자 요청을 획득합니다. */
process(); /* 그리고 처리합니다. */
} /* 가능한 한 오랫동안 */
파일, 함수, 상수 또는 변수에 대해 의미 있고 읽기 쉬운 이름을 선택하세요. 명확한 요소 이름을 만드는 데 권장되는 지침은 다음과 같습니다.
의미가 명확하고 프로그램 전체에서 일관되게 사용되는 이름을 선택하세요.
이름 축약 시에는 일관된 규칙을 따르세요. 예를 들어 "data refresher"와 관련된 여러 함수가 있다면 "dr_" 접두사를 붙여 dr_calculate, dr_update 와 같이 이름을 지을 수 있습니다.
의도하지 않은 의미를 나타낼 수 있는 글자 조합은 피하세요. 예를 들어 입력 문자를 나타내는 변수 이름으로 "in_char"라고 짓는 것이 "inch"보다 낫습니다.
가독성을 높이기 위해 이름 안에 밑줄을 사용하세요. 예를 들어 get_best_fit_model, load_best_estimate_model 과 같이 사용할 수 있습니다.
고유한 문자 수(시스템에서 허용하는 범위 내에서)를 고려하여 이름을 할당하세요.
더 긴 이름을 사용하여 가독성을 높이세요. 하지만 이름이 너무 길면 프로그램을 이해하기 어렵고 적절한 들여쓰기를 사용하여 프로그램 구조를 표현하기 어려울 수 있습니다.
네 글자보다 긴 이름은 최소 두 글자 이상 다르게 짓는 것이 좋습니다. 예를 들어 sysstat와 syssts는 비슷해 보여서 혼동하기 쉽습니다. 밑줄을 추가하여 sys_stat와 sys_sts처럼 구별하는 것이 좋습니다.
대소문자만으로 이름을 고유하게 만들려고 하지 마세요. C는 대소문자를 구분하지만(LineLength와 linelength는 서로 다른 이름입니다), 모든 이름을 대문자 또는 소문자로만 사용하는 것은 혼란을 야기할 수 있습니다. 철자는 같지만 대소문자만 다른 두 변수를 정의하지 마세요.
변수나 typedef(또는 struct)에 이미 사용된 이름과 똑같은 이름을 사용하지 마세요. C에서는 허용되지만 프로그램의 가독성을 떨어뜨릴 수 있습니다.
일부 표준적인 짧은 이름들이 아래 예시에 나와 있습니다. 의미가 명확하다면 이러한 짧은 이름들을 사용하는 것이 허용되지만, buffer_index와 같이 더 설명적인 이름을 사용하는 것을 권장합니다.
예: 표준적인 짧은 이름
c 문자 (characters)
i, j, k 인덱스 (indices)
n 카운터 (counters)
p, q 포인터 (pointers)
s 문자열 (strings)
함수 내에서 사용되는 지역 변수의 이름을 지을 때, 전역 변수 이름과 똑같이 짓지 마세요. 똑같은 이름을 사용하면 숨겨진 변수가 생겨 여러분이 의도한 대로 프로그램이 작동하지 않을 수 있습니다. 다음 예시에서 내부 변수 "total"은 외부 변수 "total"을 가리게 됩니다. 수정된 예시에서는 이러한 중복을 피하기 위해 내부 변수의 이름을 "grand_total"로 변경했습니다.
예: 숨겨진 변수
int total;
int func1(void)
{
float total; /* 이것은 숨겨진 변수입니다 */
...
}
int total;
int func1(void)
{
float grand_total; /* 내부 변수는 고유합니다 */
...
}
서로 다른 함수에서는 같은 이름을 가진 변수를 선언할 수 있습니다. 그러나 똑같은 이름은 변수들이 똑같은 의미를 가질 때만 사용해야 합니다. 만약 두 변수의 의미가 비슷하거나 우연히 같은 경우라면 혼란을 피하기 위해 고유한 이름을 사용하세요.
다음과 같은 대문자 표기법 스타일은 프로그래머와 코드 독자에게 더 많은 정보를 제공하므로 권장됩니다.
예: 대문자 표기법 스타일
open_database 변수
ProcessError 함수 이름
MAX_COUNT 상수
c_ephemd C 바인딩
번역을 하며 틀린 부분이 있을수있으니 유의해서 봐주시고 틀린것이 있다면 댓글로 부탁드립니다. 원문 https://ntrs.nasa.gov/api/citations/19950022400/downloads/19950022400.pdf