#define은 왜 사용하는 걸까?
단순히 상수 처리하기 위해 define을 사용하는 것일까?이를 알기 위해선 소스 코드의 변환 과정을 알 필요가 있다.
⭐1. Build 순서
Build의 순서는 아래와 같다.
exe 파일 생성 : 소스코드 -> 전처리 -> 컴파일 -> 링크 -> 실행
mcu 헥사 파일 생성 : 소스코드 -> 전처리 -> 컴파일 -> 어셈블리어 변환 -> 헥사 파일 생성 -> MCU 다운로드
C언어를 처음 공부할 때, #define을 사용하지 않으면 전처리 과정을 거치지 않는다고 생각한 적이 있다.
#으로 시작하는 문장은 전부 전처리기 지시자임에도 #include는 전처리기라고 생각하지 않았다. 항상 C언어를 실습할 때,
의무적으로 #inlcude <stdio.h>를 작성한 폐해이다.
⭐2. 전처리란 무엇인가?
전처리란 무엇인가?
컴파일 전에 처리되는 하는 작업이고 전처리를 수행하는 장치를 전처리기라고 한다.
전처리기는 헤더 파일을 불러오거나, 소스 파일 내부의 특정 문자열을 상수 또는 문자로 치환하거나, 조건에 따라서 코드의 일부를 컴파일하거나 컴파일하지 못하게 하는 선택 기능을 제공한다.
궁금증이 하나 발생한다.
#define은 왜 사용하는가? 단순히 변수나 함수를 선언 및 호출하면 되지 않는가? 일반 변수 및 함수와 매크로(#define)의 차이는 무엇인가?
이를 이해하기 위해선 컴파일 단계를 이해할 필요가 있다.
컴파일이란 무엇인가? 기계어로 번역하는 번역기이다. 왜 기계어로 번역하는가? 소스 코드는 사람이 이해하기 쉬운 문장이며, 기계는 이해할 수 없다. 그러므로 기계가 이해할 수 있는 문장으로 번역해줘야 한다.
C언어가 생기기 이 전, 개발자들은 기계(컴퓨터, CPU)를 직접 제어하기 위해 기계어(어셈블리어)를 직접 작성하였다. 하지만 CPU는 다양했고, CPU의 종류에 따라 어셈블리어 작성하는 방법도 각기 달랐다고 하며, 간단한 프로그램에도 코드가 굉장히 길어졌다.
이 문제점을 해결하기 위해, 기계어를 직접 사람이 작성하지 않아도 되는 번역기를 개발했는데 그것이 컴파일러이다. 개발자들은 더 이상 기계의 종류를 고려하지 않아도 된다.
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef signed char s8;
typedef signed short s16;
typedef signed long s32;
unsigned char를 u8이라는 이름으로 대체한다는 것이다.
이유는 간단하다. unsigned char가 너무 길기 때문이다.
(코드를 컴파일할 때, 전처리기가 u8을 unsigned char로 자동으로 치환하기 때문에 성능에 차이는 존재하지 않는다.)
프로젝트가 점점 커지면, 코드의 길이와 트리의 댑스(Depth)가 늘어나기 때문에 큰 프로젝트일 수록 최대한 심플하게 가져갈려고 노력한다.
잘 짜여진 코드는 남들도 쉽게 이해할 수 있는 코드여야 한다. (특히 전장 업계는 코드를 줄이는 것 보다 글을 쓰듯 일부러 풀어 쓰는 경우가 많다.)
가끔 복잡한 알고리즘이나 코드로 짜는게 고수라고 생각할 수 있지만, 무조건 simple is best이다.
가독성이 낮은 코드는 절대 좋은 코드가 될 수 없다.
아래는 풀 코드이다.
간단히 코드 돌려보고 싶다면, 괜찮은 온라인 컴파일러도 많으므로 굳이 개발 환경을 동작 시킬 필요 없이 바로 빌드해볼 수 있다. 아래 링크를 통해서 바로 빌드해 볼 수 있으니 참고 바란다.
https://www.mycompiler.io/ko/new/c
#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;
int main() {
u8 l_signal8bitOut = 10;
u16 l_signal16bitOut = 65000;
u32 l_signal32bitOut = 300000000;
printf("%d!\n", l_signal8bitOut);
printf("%d!\n", l_signal16bitOut);
printf("%ld!\n", l_signal32bitOut);
return 0;
}
728x90
반응형
'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] 3. 코딩 규칙. 변수명 정하기 (0) | 2024.09.01 |
[C/C++ Tip] 2. #define의 목적 (0) | 2024.09.01 |