C/C++언어를 사용하면서
define으로 상수나 문자열을 정의해본 적이 한 번쯤은 있을 것이다
#include <iostream>
#define MAX_SIZE 1024
#define MAIN_NAME "test main"
using namespace std;
int main(void)
{
cout << MAX_SIZE << endl;
cout << MAIN_NAME << endl;
return 0;
}
CLI> ./test
1024
test main
이런 식으로 ㅋ 문자열이나 숫자를 대체할 때 많이 쓴다
근데 자주 쓰던 " #define "이란 이 친구가 생각보다 많은 기능이 있더라
그래서 정리해보려고 한다
1. 전처리기(preprocessor)
직역하자면 processor 이전이라는 뜻인데, 우리가 프로그램을 실행하면
프로세스를 실행한다고 하는데
프로세스가 실행되기 전에 먼저 처리되는 게 전처리기이다
우리의 고급 언어로 작성된 코드를 실행하는 데는 꽤 복잡한 과정이 있다
자세한 내용은 컴파일 과정을 살펴보길 추천한다
이 중 전처리기 과정은 실행 파일 생성하는 과정에서
소스 파일의 여러 지시문을 우선 처리하는 작업이다
코드 생성 X, 컴파일러가 컴파일 잘 할 수 있도록 소스를 재구성해주는 역할이다
전처리되는거는 어떤 게 있냐면
(1) 전처리 지시자
(2) Macro
(3) 조건부 컴파일 (Conditional compilation)
...
등등이 있다 ㅋ
사실 오늘 macro만 정리하려고 했는데 말이 계속 늘어나네;;
(1) 전처리 지시자 (preprocessing directives)
하여간 우리말은 너무 어려워
전처리 지시자라는 단어는 어려워 보이지만,
우리가 많이 쓰는 #include, #define, #pragma, #ifndef 등이다 ㅋ
#include
얘는 프로그램 파일의 위치를 첨부하여 하나의 파일처럼 컴파일해주고,
헤더 파일이나 다른 파일에 있는 선언 내용을 다른 파일끼리 연결해준다
사용 방식에는 두 가지가 있다 ㅋ
#include <iostream>
#include "MyClass.hpp"
표준 헤더 파일을 컴파일에 포함할 때는 <>를 사용하고
우리가 작성한 헤더 파일을 포함할 때는 ""를 사용한다
사실 섞어 써도 되긴 하는데, 표준(?)적인 문법이다
#define
얘는 글의 가장 첫 번째 예시에서 사용했는데, 상수/문자열/함수 등을 단순화해준다
define 자체는 정의하다는 뜻이지 않은가
좀 더 명확하게 이름을 붙여준다~라고 생각하면 된다
#define PERIMETER 3.14
int main(void)
{
int n = 3.14;
int n = PERIMETER;
...
이런 식으로? 그냥 상수 사용보다는 이름 붙여서 사용 ㅇㅇ
그 밖의 전처리 지시자는 링크를 참고하길 바란다
(2) 매크로 함수 (Macro function)
매크로는 직역하면 '거대한'이란 뜻인데,
마이크로(micro)의 반대되는 의미로 뭔가 하나의 큰 단위?라고 이해하면 된다
위에서 다룬 #define 지시자에 함수 정의를 전달해서 마치 함수처럼 동작하게 할 수 있다
#include <iostream>
#define PLUS(x) x+x
#define MUL(x) x*x
using namespace std;
int main(void)
{
cout << PLUS(5) << endl;
cout << MUL(5) << endl;
return 0;
}
이런 식으로 사용 가능하다
함수처럼 인자를 전달해주는 모양으로 사용이 가능하다 ㅋ
#define MY_PRINT(x)\
do{\
cout << "x는 " << endl;\
cout << x << endl;\
}while(0)\
여러 줄이라면 do-while문을 사용해서 표현도 가능하다
끝에 "\"를 써서 개행 표시해주는 거도 잊지 마시길ㅋ
요놈 참 편리함
근데 위에 위에서 사용한 상수 계산식을
매크로 함수로 만들 때는 주의해야 할 점이 하나 있다
#include <iostream>
#define PLUS(x) x+x
#define MUL(x) x*x
using namespace std;
int main(void)
{
int plus_ret = PLUS(5);
int mul_ret = MUL(5+5);
cout << plus_ret << endl;
cout << mul_ret << endl;
return 0;
}
CLI> ./test.out
10
35
롸? 왜 아래 꺼는 35로 찍힐까
10 * 10을 예상했겠지만.. 전처리기는 치환해줄 뿐이다
즉, MUL(X)는 5+5*5+5로 바뀌기 때문에
사칙연산 우선순위에 따라 결과가 예상과 다르게 나온 것이다 ㅋ
그래서 상수식에 대해 매크로를 작성할 때는
#define MUL(x) (x)*(x)
이렇게 괄호를 묶어서 사용해야 한다
# 연산자 사용
전처리 지시자에는 #연산자를 사용하여 토큰 단위 연산을 사용할 수 있다
#include <iostream>
#define PLUS(X)\
do{\
cout << ""#X"의 덧셈은" << ((X)*(X)) << "입니다." << endl;\
}while(0)\
using namespace std;
int main(void)
{
PLUS(5);
PLUS(3+4);
return 0;
}
5의 덧셈은25입니다.
3+4의 덧셈은49입니다.
요런 식으로~~ # 큰따옴표 + 파라미터를 포함해서 사용하면
문자열 상수로 변환해준다
(3) 조건부 컴파일 (Conditional compilation)
조건부 컴파일은 조건에 따라 컴파일한다라는 뜻인데
조건이 맞으면 처리하고 안 맞으면 안 처리한다는거겠쥬?
내가 가장 많이 쓰는 건 주석처리를 사용할 때다
#if ~ [#elseif] ~ [#else] ~ #endif
주석 처리한걸 좀 더 명확하게 보여드릴라고 캡처로 가져와봤다
결과는 3만 출력된다
#ifdef~ 조건 사용
우리가 코드를 짜다보면 운영체제에 따라서,
또는 어떤 라이브러리의 버전에 따라서 추가해야 할 헤더 파일도 달라지고
그럴 때가 있다... 근데 이때마다 코드를 수정하는 건 좀 그렇다 많이 그렇다
#ifdef __unix__ /* __unix__ is usually defined by compilers targeting Unix systems */
# include <unistd.h>
#elif defined _WIN32 /* _Win32 is usually defined by compilers targeting 32 or 64 bit Windows systems */
# include <windows.h>
#endif
이런 식으로 해주면, 윈도이건 유닉스이건
알아서 컴파일할 때 포함되어야 할 헤더 파일을 포함시켜 준다
#if RUBY_VERSION == 190
# error 1.9.0 not supported
#endif
이런 식으로 특정 조건이 아닐 때 에러를 뱉도록 해줄 수도 있다
그럼 이만
* 참고 링크 *
http://www.tcpschool.com/c/c_prepro_preprocessor
코딩교육 티씨피스쿨
4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등
tcpschool.com
https://ko.wikipedia.org/wiki/C_%EC%A0%84%EC%B2%98%EB%A6%AC%EA%B8%B0
C 전처리기 - 위키백과, 우리 모두의 백과사전
매크로는 컴퍼일러에게 코드의 특성을 알려주는 키워드이다. 따라서 기계어로 컴파일 과정에서 필요한 요소이고, 매크로 자체가 기계어 코드로 생성되지는 않지만 특정 코드를 제어하는데 사
ko.wikipedia.org
'BackEnd > C랑 C++' 카테고리의 다른 글
Boost로 시간 값 사용해보기 (0) | 2022.11.29 |
---|---|
Boost::program_options 사용기 (0) | 2022.07.26 |
Error 해결: boost::shared_ptr<boost::asio::io_context>::operator* (0) | 2022.02.04 |
STRUCT와 UNION을 알아보자 (0) | 2021.07.12 |
C++ 스마트 포인터를 알아보자 - (2) shared_ptr (0) | 2021.06.25 |