C/C++ Tip 관련 세번 째 글이다.
뭘 작성할까 고민 하다가 코딩만큼 중요한 변수명 정하는 것으로 결정했다.
변수명 정하기가 중요한 이유는 가독성 때문이다.
가독성이 높은 코드는 내가 아닌 남에게 보여주기 위함이다.
여기서 남이란 후배, 상사 뿐만 아니라 한달 뒤의 '나'도 남에 포함된다.
코드를 봤을 때 결과가 독서하는 것처럼 바로 유추가 되어야 한다.
변수명 규칙은 네 개를 꼭 기억하면 된다.
함수의 input parameter(입력 인자, 입력 파라미터)는 i_{변수명}
함수의 output parameter(출력 인자, 출력 파라미터)는 o_{변수명}
함수의 local 변수(로컬, 지역 변수)는 l_{변수명}
static 변수(정적 변수) 혹은 전역변수는 {변수명}
하나의 예시를 보겠다.
#include <stdio.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef signed char s8;
typedef signed short s16;
typedef signed long s32;
void manyFunc(const u8 i_a, const u8 i_b, u8* const o_sum, u8* const o_sub){
u8 l_sum, l_sub;
l_sum = i_a + i_b; //5
l_sub = i_a - i_b; //6
*o_sum = l_sum;
*o_sub = l_sub;
}
u8 addFunc(const u8 i_a, const u8 i_b){
u8 l_sum;
l_sum = i_a + i_b; //3
return l_sum;
}
int main() {
u8 l_result; //1
u8 l_addResult, l_subResult;
l_result = addFunc(2, 1); //2
manyFunc(2, 1, &l_addResult, &l_subResult); //4
printf("%d\n", l_result); //7
printf("%d, %d\n", l_addResult, l_subResult); //8
return 0;
}
갑자기 typedef가 나와서 당황한다면 이 글을 읽고 오는 것을 추천한다.
https://coding-yoon.tistory.com/246
u8 l_result;
u8 l_addResult, l_subResult;
l_result 를 보면, 우린 규칙을 토대로 로컬 변수임을 알 수 있다.
이 변수명의 장점은 처음에는 어색할 수 있지만, 이렇게 규칙을 정해놓으면, 보는 것만으로도 로컬 변수인지 바로 확인할 수 있다.
l_result, l_addResult, l_subResult 로 선언한 이유는 main 함수의 로컬 변수이기 때문이다.
코드를 계속 보겠다.
l_result = addFunc(2, 1);
addFunc 함수에 진입한다.
u8 addFunc(const u8 i_a, const u8 i_b){
u8 l_sum;
l_sum = i_a + i_b;
return l_sum;
}
코드의 인자를 보고 의문이 드는게 있을 수 있다.
i_a, i_b는 입력 파라미터에 왜 const를 붙이는 걸까?
const를 붙인다는 거는 변수의 값을 수정하는 것을 금하는 것을 뜻한다.
이유는 하나이다. 입력 파라미터의 원본을 훼손되는 것을 방지하기 위함이다.
입력 파라미터의 훼손을 막으며, 계산된 값을 로컬 변수인 l_sum을 리턴하는 동작이다.
출력 파라미터는 o_{변수명}을 쓴다고 하지 않았는가?
출력 변수가 하나이기 때문에 그냥 return으로 뽑는게 더 효율적이다.
기억하자.
출력 변수가 하나일 때는 return 을 사용하자.
void manyFunc(const u8 i_a, const u8 i_b, u8* const o_sum, u8* const o_sub){
u8 l_sum, l_sub;
l_sum = i_a + i_b;
l_sub = i_a - i_b;
*o_sum = l_sum;
*o_sub = l_sub;
}
이제 manyFunc 라는 함수에 도달했다.
이번엔 파라미터에 더 이상한 값들이 보일 것이다. const의 위치도 이상하고.
심지어 여기서부터는 포인터가 사용된다.
C의 꽃인 포인터.
만약, 위 코드에 이해의 어려움이 있다면 포인터 공부를 조금 더 하고 오는 것을 추천한다.
출력 파라미터가 하나 일때는 return을 사용한다고 했다.
두 개일 때는 void 타입을 사용하며, 포인터를 사용한다.
규칙은 간단하다. 입력 파라미터의 원본 수정은 당연히 금지이다.
입력 파라미터를 통해 계산이 완료된 값은 로컬 변수에 저장된다.
저장 후, 포인터에 접근하여 출력 파라미터에 값을 기입한다. (o_{변수명})
manyFunc(2, 1, &l_addResult, &l_subResult);
메인 함수로 돌아와 l_addResult, l_subResult 에 출력 파라미터에 저장하는 간단한 소스코드이다.
현재 위 규칙을 통해 소스코드를 작성할려고 노력하고 있다.
위 규칙에서 중요한 것은 입력 파라미터와 출력 파라미터에는 별도의 로직이 들어가지 않는다는 것이다.
어떠한 계산 및 로직 처리가 된 결과 값은 오로지 로컬 변수에 담는 것이다.
이렇게 되면 나중에 유지보수하기가 훨씬 편하다.
지금 당장에서 코드를 봤을 때는 괜히 더 복잡해지고, 불필요하게 로직이 들어갔다고 생각할 수 있지만, 코드가 몇 백줄, 소스코드가 몇 십개로 쪼개진다면,
위 규칙은 엄청난 장점으로 다가올 것이다.
하지만 위 규칙을 숙지하기 이 전, 포인터의 이해를 전제로 한다.
하지만 위 규칙이 정답만은 아니다. 자신이 생각하는 혹은 회사의 설계 룰대로 습관이 벤다면, 한달 후 내 코드를 다시 봤을 때, 코드 분석하는 시간이 훨씬 줄어든 자신을 볼 수 있을 것이다.
'C언어 30강' 카테고리의 다른 글
[C/C++ Tip] 6. UNION 공용체와 STRUCT 구조체로 패킷 만들기 (2) | 2024.09.04 |
---|---|
[C/C++ Tip] 5. 구조체 패딩의 필요성 (0) | 2024.09.04 |
[C/C++ Tip] 4. 구조체 활용: 효율적인 데이터 관리 (2) | 2024.09.02 |
[C/C++ Tip] 2. #define의 목적 (0) | 2024.09.01 |
[C/C++ Tip] 1. 개발하기 전, typedef 별명 부여. (0) | 2024.09.01 |