조건부 컴파일
-> 컴파일을 하는데 조건을 두어 컴파일 할지, 말지를 결정한다.

사용자가 값을 입력하여 컴파일 여부를 결정할 수 없다.
-> 값을 입력하는 시점은 컴파일이 모두 완료된 런타임 시점

(전역 변수나 지역 변수를 통해 비교 불가능)
-> 컴파일 이전에 조건을 비교해야 하기 때문에 전처리기 단계에서 조건을 비교한다.

##1. #if ~ #endif
-> if문을 사용하듯이 사용하면 된다.
-> 조건이 참일 경우 컴파일을 수행한다.

 

if       -> #if

else if -> #elif

else    -> #else

 

#define TEST 1

void main()
{
#if TEST > 0
 cout << "TEST는 0보다 크다." << endl;
#endif
}

#if는 기존 if와는 다르게 시작 구간과 종료 구간이 {}안이 아닌 #if를 선언한 시점부터 #endif 이전까지이다.

그래서 #if를 끝내려면 마지막에 #endif를 적어줘야한다.

 

 

#2 조건부 컴파일 #ifdef

-> define으로 정의되어 있다면 컴파일을 수행

#define ABCD

void main()
{
#ifdef ABCD
  cout << "ABCD는 정의되어 있음" << endl;
#endif
}

 

#3 조건부 컴파일_#ifndef ~ #endif

-> ifdef의 반대 의미이다.

-> define으로 정의되어 있지 않다면 수행

-> 주로 사용하는 방법은 1회만 수행하길 원할 때 사용한다.

#define ABCD

void main()
{
#ifndef ABCD
  cout << "ABCD는 정의되어 있지 않음" << endl;
#endif
}

 

 

 

 

 

'Programming > C++ Basic' 카테고리의 다른 글

C++ 레퍼런스 자료형  (0) 2020.09.08
C++ 파일 분할(.cpp, .h)  (0) 2020.09.08
C++ 매크로(#define)  (0) 2020.09.07
C++ 함수 포인터  (0) 2020.09.07
C++ 공용체(union)  (0) 2020.09.07

매크로

-> 단순 치환

-> #define으로 정의한다.

# : 전처리 지시자

-> 컴파일 이전에 수행

define : 정의하다.

-> 컴파일 이전에 정의하라고 명령.

 

#1 매크로 상수

#define 매크로이름 치환할 값

 

매크로 상수 사용 시 주의사항

-> 단순 치환이기 때문에 세미콜론을 작성할 경우 세미콜론까지 치환해버린다.

예)

#define PI 3.14f;

// 입력
cout << PI << endl; 

// 출력
cout << 3.14f; << endl;

 

매크로 이름 뒤에 치환할 값이 없다면 공백으로 처리한다.

예)

#define PI 

// 입력
cout << PI << endl; 

// 출력
cout <<  << endl;

 

#define 매크로는 주로 배열의 크기를 다룰 때 사용을 한다.

#define MAX_SIZE 512

void main()
{
  int iArr[MAX_SIZE] = {};
}

#2 매크로 함수

-> 매크로를 함수처럼 사용하는 것

#define 매크로이름()  정의부 구현
#define SQUARE(n) n * n

이것은 다음 함수와 같다.

int Square(int _n)
{
  return _n *_n;
}

일반 함수 호출

-> 함수가 위치한 호출 번지로 이동 -> Stack 영역 할당 및 매개 변수 복사

-> 연산 -> 값 반환 및 Stack 영역 정리 -> 호출했던 위치로 복귀

 

매크로 함수 호출

-> Stack 영역이 할당 및 복사가 없다.

-> 속도가 빠르다.

-> 함수 호출을 위한 연산들이 필요 없어진다.

 

매크로 함수의 주의점

 

#1 연산을 수행할 때 연산자 우선순위를 명확하게 표시해야한다.

예)

#define SQUARE(n) n * n
cout << SQUARE(2 + 2) << endl;		// cout << 2 + 2 * 2 + 2 << endl;

이렇게 되면 연산자 우선순위가 곱셈을 먼저 수행해서 2 * 2 + 2 + 2 = 8이 된다.

하지만 다음과 같이 #define 함수를 정의할 때 우선순위를 정해주면 원하는 값이 나오게 된다.

#define SQUARE(n) (n) * (n)
cout << SQUARE(2 + 2) << endl;		// cout << (2 + 2) * (2 + 2) << endl;

 

#2 함수의 정의부가 길 경우
-> 매크로 함수는 줄 바꿈을 할 수 없다.
-> 무조건 1줄로만 매크로로 인식한다. 
-> 이를 해결하기 위해 줄바꿈 전에 \(역슬러쉬)로 다음 줄에도 매크로 이어진다. 라고 알려주어야 한다.

#define SQUARE(n) \
n * n

-> 단, \ 뒤에 공백 문자가 올 경우 컴파일 오류가 발생한다!

#define SQUARE(n) \공백
n * n

 

#3 디버깅이 불가능하다

-> 매크로 함수는 짧지만 자주 사용하는 함수를 매크로 함수로 정의하는 것이 좋다.

예를 들어 포인터 할당을 해제하는 경우가 생겼을 때

if(p != nullptr)
{
  delete p;
  p = nullptr;
}

다음과 같이 매크로를 지정하여 손쉽게 할당 해제가 가능하다.

#define SAFE_DELETE(p) if(p) { delete p; p = nullptr; }

함수()
{
코드 블럭
SAFE_DELETE(포인터 값);
}

#define 으로 정의된 상수는 항상 괄호로 감싸준다.

#define NUM (1)

상수는 #define 보다 const 상수 변수로 선언한다.

 

'Programming > C++ Basic' 카테고리의 다른 글

C++ 파일 분할(.cpp, .h)  (0) 2020.09.08
C++ 조건부 컴파일(#if, #ifdef, #ifndef 등)  (0) 2020.09.07
C++ 함수 포인터  (0) 2020.09.07
C++ 공용체(union)  (0) 2020.09.07
C++ 열거체(enum)  (0) 2020.09.06

함수 포인터

-> 함수의 주소를 저장하는 변수

-> 함수 포인터는 코드 영역에 들어간다.

-> 할당 시점 : 프로그램 시작시 

-> 할당 종료 : 프로그램 종료시

 

 

함수를 호출할 때 함수명 + ()를 이용한다.

-> 연산자 ()를 제거하면 함수명만 남게된다.

-> 함수명은 함수의 주소를 가지고 있다.

-> cout을 통해 함수명만 호출하면 함수의 주소가 나오게된다.

 

함수 포인터의 형태

int Add(int _a, int _b)
{
	return _a + _b;
}	

반환타입(* 변수명) (인자타입, 인자타입, 인자타입... )
int(*ptr)(int, int) = Add;
    
cout << ptr(10, 20) << endl;

 

일반 함수 switch 사용

int iA = 0, iB = 0, iSelect = 0, iRes = 0;
	cin >> iA >> iB;
	cout << "1.더하기 2.빼기 3.곱하기 4.나누기" << endl;
	cout << "============================================" << endl;
	cout << "입력: ";
	cin >> iSelect;

	switch (iSelect)
	{
	case 1:
		iRes = Add(iA, iB);
		break;
	case 2:
		iRes = Min(iA, iB);
		break;
	case 3:
		iRes = Mul(iA, iB);
		break;
	case 4:
		iRes = Div(iA, iB);
		break;
	default:
		break;
	}

	cout << "연산 결과: " << iRes << endl;

 

함수 포인터 switch 사용

	int iA = 0, iB = 0, iSelect = 0, iRes = 0;
	cin >> iA >> iB;
	cout << "1.더하기 2.빼기 3.곱하기 4.나누기" << endl;
	cout << "============================================" << endl;
	cout << "입력: ";
	cin >> iSelect;

	int(*ptr)(int, int) = nullptr;

	switch (iSelect)
	{
	case 1:
		ptr = Add;
		break;
	case 2:
		ptr = Min;
		break;
	case 3:
		ptr = Mul;
		break;
	case 4:
		ptr = Div;
		break;
	default:
		break;
	}
	cout << "연산 결과: " << ptr(iA, iB) << endl;

switch를 통해 함수 포인터를 사용하였는데 코드가 너무 길다고 판단이 된다.

이를 해결하기 위해서 함수 포인터의 배열을 사용해보자.

 

함수 포인터 배열 사용

int Add(int _a, int _b)
{
	return _a + _b;
}
int Min(int _a, int _b)
{
	return _a - _b;
}
int Mul(int _a, int _b)
{
	return _a * _b;
}
int Div(int _a, int _b)
{
	return _a / _b;
}

int iA = 0, iB = 0, iSelect = 0, iRes = 0;
	cin >> iA >> iB;

int(*ptr[4])(int, int) = { Add, Min, Mul, Div };

cout << "연산 결과: " << ptr[iSelect - 1](iA, iB) << endl;

switch문을 사용했을 때와 결과는 같고 훨씬 더 코드가 간결해진 것을 볼 수 있다.

'Programming > C++ Basic' 카테고리의 다른 글

C++ 조건부 컴파일(#if, #ifdef, #ifndef 등)  (0) 2020.09.07
C++ 매크로(#define)  (0) 2020.09.07
C++ 공용체(union)  (0) 2020.09.07
C++ 열거체(enum)  (0) 2020.09.06
C++ 경로  (0) 2020.09.02

공용체(union)

-> 사용자 정의 자료형

-> 구조체와 비슷하다.

 

공용체의 형태

	union 자료형이름
	{
		멤버 변수
	}

 

공용체 선언

tagBox tBox;
uniBox uBox;

 

공용체 초기화

tagBox tBox = {};
uniBox uBox = {};

 

 

공용체의 각 멤버 초기화

tagBox tBox = {10, 3.14};
uniBox uBox = {10, 3.14f};

 

 

구조체와 공용체의 차이점

-> 구조체 각 멤버들이 메모리에 할당이 된다.

-> 공용체 메모리가 하나만 할당한 후 모든 멤버들이 공유한다.

(즉, 공용체에 들어있는 멤버 변수들은 모두 같은 메모리 공간을 사용 한다.)

struct tagBox
{
	int iA;
	double dB;
};
union uniBox
{
	int iA;
	float fB;
};

void main()
{
	tagBox		tBox = {10, 3.14};
	uniBox		uBox = {10};

	cout << "&tBox.iA: " << &tBox.iA << endl;
	cout << "&tBox.dB: " << &tBox.dB << endl;
	cout << "-----------------------------------------" << endl;
	cout << "&uBox.iA: " << &uBox.iA << endl;
	cout << "&uBox.dB: " << &uBox.fB << endl;

}

 

공용체의 크기
-> 공용체의 크기는 멤버들 중 가장 큰 멤버 변수의 크기로 설정된다.

union uniBox
{
	int iA;
	double dB;
};

void main()
{	
	uniBox		uBox = {};

	cout << "공용체의 크기: " << sizeof(uBox) << endl;
}

공용체는 안에 있는 멤버 변수의 값 변경시 가장 마지막에 변경한 변수의 값만 적용이 되고 나머진 쓰레기 값이 된다.

union tagTest
{
	int iA;
	float iB;
};


void main()
{

	tagTest test;
	test.iA = 10;
	cout << test.iA << endl;
	test.iB = 5.f;
	cout << test.iB << endl;
	cout << test.iA << endl;
}

 

'Programming > C++ Basic' 카테고리의 다른 글

C++ 매크로(#define)  (0) 2020.09.07
C++ 함수 포인터  (0) 2020.09.07
C++ 열거체(enum)  (0) 2020.09.06
C++ 경로  (0) 2020.09.02
C++ 입출력 스트림 버퍼, 단일 문자 입/출력 함수  (0) 2020.09.02

+ Recent posts