본문 바로가기
프로그래밍/소프트웨어 공학 (완)

8장 - 상수, 수식, 문장 작성 규칙: 안전하고 효율적인 코딩의 완성 (57)

by 서가_ 2025. 6. 19.
반응형

상수, 수식, 문장 작성 규칙: 안전하고 효율적인 코딩의 완성

코딩 규칙 시리즈의 마지막 편에서는 상수 사용, 수식 작성, 그리고 제어문 작성에 관한 세부 규칙들을 살펴보겠습니다. 이러한 규칙들은 코드의 안전성과 가독성을 한층 더 높여줍니다.

 

상수 사용 규칙: 명확성과 안전성

8진수 사용 금지

8진수 표기법은 가독성을 떨어뜨리고 혼란을 야기할 수 있으므로 사용하지 않는 것이 좋습니다.

피해야 할 표기:

int octal = 0377;  // 8진수 표현 - 혼란 야기

권장하는 표기:

int hexa = 0xFF;   // 16진수 표현 - 명확함
int decimal = 255;  // 10진수 표현 - 직관적

숫자 리터럴 대신 상수 사용

코드에 직접 숫자를 입력하는 하드 코딩은 의미 파악을 어렵게 만들고 유지보수를 힘들게 합니다.

하드 코딩의 문제:

int tri_area = 10*5/2;  // 숫자의 의미를 알기 어려움

상수를 활용한 개선:

const int base_line = 10;  // 밑변
const int height = 5;      // 높이
int tri_area = base_line * height / 2;  // 삼각형 면적 공식이 명확

상수의 자료형 명시

부호 없는 자료형을 사용할 때는 u를 붙여 자료형을 명확히 표시합니다.

모호한 표기:

#define SIZE 20;

명확한 표기:

#define SIZE 20u;  // unsigned 타입임을 명시

수식 작성 규칙: 가독성과 명확성

단항 연산자의 올바른 표기

단항 연산자(++, --)는 피연산자와 붙여 써야 어떤 변수에 적용되는지 명확히 알 수 있습니다.

잘못된 간격:

a ++  // 공백으로 인한 혼동 가능성

올바른 표기:

a++   // 명확한 연산자 적용

이항 연산자의 올바른 표기

이항 연산자(+, -, *, /)는 전후에 공백을 넣어 연산자와 피연산자를 명확히 구분합니다. 단, 점(.) 연산자는 예외입니다.

가독성이 떨어지는 표기:

a=b+c*d-e;  // 연산자와 피연산자 구분이 어려움

가독성이 좋은 표기:

a = b + c * d - e;  // 연산자와 피연산자가 명확히 구분

삼항 연산자의 명확한 표기

삼항 연산자(?:)를 사용할 때는 조건식을 괄호로 묶어 우선순위를 명확히 합니다.

애매한 표기:

a > b ? x : -x;  // 조건 부분이 불분명

명확한 표기:

(a > b) ? x : -x;  // 조건이 명확히 구분됨

증강 연산자의 안전한 사용

증강 연산자(복합 할당 연산자)는 다른 연산과 함께 사용하지 말고 별도의 줄에 작성합니다.

혼란을 야기하는 코드:

sum = kor + (++eng);  // 연산 순서가 불분명

명확한 코드:

++eng;              // 증가 연산을 별도로 수행
sum = kor + eng;    // 단순한 덧셈 연산

연산자 우선순위 명시

연산자가 3개 이상인 복잡한 수식에서는 괄호를 사용하여 우선순위를 명확히 표현합니다.

우선순위가 불분명한 수식:

result = a + b * c - d / e;

괄호로 우선순위를 명시한 수식:

result = a + (b * c) - (d / e);

sizeof 함수의 올바른 사용

sizeof 함수의 인자로는 변수나 자료형을 사용하고, 복잡한 수식은 피합니다.

권장하는 사용법:

int arr[10];
size_t arraySize = sizeof(arr);
size_t intSize = sizeof(int);

제어문 작성 규칙: 안전한 프로그램 흐름

switch 문의 완성도

break 문의 명시적 사용

switch 문에서 각 case는 break 문으로 명확히 종료해야 합니다. break 문이 없을 때는 의도적임을 주석으로 표시합니다.

의도가 불분명한 코드:

switch(grade) {
    case 'A':
        printf("Excellent");
    case 'B':
        printf("Good");
        break;
}

의도가 명확한 코드:

switch(grade) {
    case 'A':
        printf("Excellent");
        // break 문이 없어 case 'B'로 넘어감 (의도적)
    case 'B':
        printf("Good");
        break;
    default:
        printf("Invalid grade");
        break;
}

default 문의 필수 포함

switch 문은 반드시 default 문으로 종료하여 예상하지 못한 값에 대한 처리를 해야 합니다.

불완전한 switch 문:

switch(choice) {
    case 1:
        processOptionOne();
        break;
    case 2:
        processOptionTwo();
        break;
}

완성된 switch 문:

switch(choice) {
    case 1:
        processOptionOne();
        break;
    case 2:
        processOptionTwo();
        break;
    default:
        printf("Invalid choice");
        break;
}

반복문 작성 규칙

goto 문 사용 금지

goto 문은 프로그램의 흐름을 복잡하게 만들고 디버깅을 어렵게 하므로 사용하지 않습니다.

대신 구조적 제어문 사용:

// goto 대신 while이나 for 문 활용
while(condition) {
    if(exitCondition) {
        break;  // goto 대신 break 사용
    }
    // 처리 내용
}

for 문에서 실수 사용 금지

for 문의 제어 변수로는 정수를 사용하고, 실수는 피합니다.

문제가 있는 for 문:

float i = 1.1;
for(i = 1.1; i < 2.5; i = i + 0.1) {  // 부정확한 실수 연산
    // 처리 내용
}

안전한 for 문:

int i;
for(i = 1; i < 15; i++) {  // 정수로 제어
    float value = 1.1 + (i * 0.1);  // 필요시 실수 계산
    // 처리 내용
}

제어 변수의 올바른 사용

for 문의 제어 변수는 반복 제어 목적으로만 사용해야 합니다.

잘못된 사용:

int i, j = 10;
for(i = 0; i < 10; i++) {
    i = i + j;  // 제어 변수를 계산에 사용 - 반복 횟수 예측 불가
}

올바른 사용:

int i, j = 10;
for(i = 0; i < 10; i++) {
    int temp = i + j;  // 별도 변수를 사용한 계산
    // temp 활용
}

break 문 사용 최소화

반복문에서 break 문은 가능한 한 번만 사용하여 프로그램 흐름을 예측 가능하게 만듭니다.

여러 break 문 사용:

int i = 0;
while(1) {
    if(i == 0) {
        break;  // 첫 번째 break
    } else if(i == 20) {
        break;  // 두 번째 break
    }
    i++;
}

단일 break 문 사용:

int i = 0;
while(1) {
    if((i == 0) || (i == 20)) {
        break;  // 조건을 합쳐서 한 번만 break 사용
    }
    i++;
}

조건문 완성 규칙

if ~ else 문의 완성

if 문은 항상 else 문으로 완성하여 모든 경우를 처리합니다.

불완전한 조건문:

int score;
printf("점수 입력:");
scanf("%d", &score);
if(score >= 70) {
    printf("PASS");
}
// 70점 미만일 때의 처리가 없음

완성된 조건문:

int score;
printf("점수 입력:");
scanf("%d", &score);
if(score >= 70) {
    printf("PASS");
} else {
    printf("FAIL");  // 모든 경우를 처리
}

실제 개발에서의 적용

코드 안정성 향상

이러한 규칙들을 따르면:

  • 런타임 오류 발생 가능성 감소
  • 예상치 못한 프로그램 동작 방지
  • 디버깅 시간 단축

팀 개발에서의 장점

  • 일관된 코드 스타일: 팀원 누구나 이해하기 쉬운 코드
  • 오류 예방: 공통된 실수 패턴 방지
  • 유지보수 효율성: 명확한 로직 구조로 수정 용이

자동화 도구 활용

현대 IDE들은 다음과 같은 기능을 제공합니다:

  • 정적 분석: 잠재적 오류 사전 감지
  • 코드 포맷팅: 수식과 제어문 자동 정리
  • 린팅: 코딩 규칙 위반 실시간 감지

마치며: 코딩 규칙의 진정한 가치

이번 시리즈를 통해 프로그래밍 언어의 역사부터 구체적인 코딩 규칙까지 살펴보았습니다. 이러한 규칙들이 처음에는 번거롭게 느껴질 수 있지만, 다음과 같은 궁극적인 목표를 달성하기 위한 필수 요소입니다:

코드의 품질 향상

  • 가독성과 유지보수성 개선
  • 오류 발생 가능성 최소화
  • 성능과 안정성 확보

개발 효율성 증대

  • 팀워크 향상
  • 개발 시간 단축
  • 코드 리뷰 품질 개선

전문성 향상

  • 체계적인 개발 습관 형성
  • 산업 표준 준수
  • 지속 가능한 소프트웨어 개발

좋은 코딩 규칙은 단순한 약속이 아닙니다. 수많은 개발자들의 경험과 지혜가 담긴 베스트 프랙티스입니다. 이러한 규칙들을 내재화하여 더 나은 개발자로 성장하시길 바랍니다.

코드는 컴퓨터를 위한 명령어이지만, 동시에 사람을 위한 의사소통 도구입니다. 명확하고 아름다운 코드를 작성하는 것은 개발자의 중요한 덕목 중 하나입니다.

반응형