이번 글은 매크로와 레퍼런스에 관련한 내용이다. 이 둘은 서로 전혀 상관이 없지만. 내가 같은날 배웠기 때문에 같이 적는다.
매크로란 보통 전처리기에 의해 미리 정해둔 문구이다. 함수와 크게 다르지 않지만 약간 차이가 있다.
먼저 매크로를 선언하는 방법은 가장 위에 #을 이용한 선언이다. 보통 자주 사용하는 문구들을 자동화하기 위하여 저장해둔 것이다. 예를들어 π(PI)는 보통 3.14를 의미한다. 하지만 매번 3.14를 치기엔 유독 귀찮은 관계로 나는 다음과같이 매크로화 하려 한다.
#define PI 3.14f
이제부터 나는 PI만 치면 자동으로 3.14f라는 숫자가 입력될 것이다.
이와 같은경우는 EOF,SEEK_SET등 이미 몇번 사용해왔다.
이렇게 #을 치고 define을 하면 새로이 매크로를 정의하겠다는 뜻이다.
이것은 PI라는 문자를 자동으로 3.14f로 치환한 것이다.
또한 다음과같이 함수처럼 사용할 수도 있다.
#define ADD(a,b) a+b
이제 나는 어디서든 ADD(a,b)를 하면 a+b한 값을 받을 수 있게 된다. a와b의 자료형은 정수건 실수건 전혀 상관이 없다.
이렇게 매크로화하는것의 장점은
1. 어떤 자료형이건 상관없이 매크로로 불러낼 수 있다.
2. 또한 별도로 함수를 선언할 필요 없이 가장 위에 매크로화 시켜주면 끝이다.
3. 함수보다 속도가 빠르다.
라는것이고
단점으로는
1. 문자를 치환하는 행위이기 때문에 매크로의 정의를 잘못한다면 컴파일러는 매크로를 불러내는 시점에 오류가 있다고 생각한다. 그렇기때문에 무분별한 매크로의 남용은 디버깅을 어렵게 한다.
2. 또한 같은 이유로 매크로 내 ";" 를 적는다면 매크로 이후의 구문은 자동으로 읽지 않기 때문에 사용을 금한다.
3. 복잡한 함수의 구현은 어렵다. 그냥 함수를 적는게 나을정도이다.
4. 문자를 단순 치환하는것이기때문에 연산 우선순위에 의한 오류가 가능하다.
4번은 예시를 들어보겠다
#define MUL(x) x*x
이렇게 하면 x의 제곱을 받을 수 있게 되는데 만일 내가
MUL(2+3);
이라고 하면 어떻게 될까?? 5의 제곱이 나올것같으나 아니다. 컴퓨터의 연산과정은
2+3 * 2+3
이 되므로 *연산이 우선되니 2+6+3으로 11이 반환 되는것이다.
또한 추후에 파일을 include 할 일이 많은데 동일한 매크로가 선언된 파일을 여러개 include 하면 오류가 발생하게 된다.
그것을 방지하기 위해 전처리 조건문이 존재한다.
#if 전처리 조건문 시작
#elif else if와 동일
#else else와 동일
#endif 조건문을 끝낸다.
#ifdef 전처리기 정의 여부 // 만약에 define으로 이미정의되어 있다면 실행
이후 elif,else,endif는 동일하다
#ifndef 전처리기 정의 여부 // 만약에 define으로 정의되어 있지 않다면 실행
이후 elif,else,endif는 동일하다
그러니 모든 파일이 매크로를 정의할 때마다 이 #ifndef를 이용해야하니 여간 귀찮은게 아니다.
하지만 최근엔 #pragma once로 동일한 파일을 한번만 불러오게끔 해주는 명령어가 있어 비교적 편해지긴 했다.
레퍼런스
우리는 다른 함수에서 선언된 값을 이용하기 위하여 포인터라는 개념을 사용했었다.
레퍼런스는 이와 동일한 기능을 가졌다.
레퍼런스는 참조라는 뜻을 가지고 있다. 그래서 그냥 값을 전달해도 원본을 참조하여 조작이 가능하게 된다.
레퍼런스는 포인트 당시 주소값 추출 연산자 &와 동일하다. 레퍼런스를 이용하여 값을 변경해보겠다.
void test(int& rTemp, int& rDest) {
rTemp = 100;
rDest = 200;
}
void main(void)
{
int iTemp = 10;
int iDest = 20;
test(iTemp, iDest);
cout << iTemp << endl << iDest << endl;
}
메인부터 보겠다.
iTemp를 10, iDest를 20으로 선언하였고
test함수에는 int형 레퍼런스 두개 rTemp와 rDest를 받았다.
그리고 test함수에 포인터가 아닌 그냥 iTemp와 iDest를 그대로 넣어주었음에도 레퍼런스를 통해 원본에 접근하여 값이 100과 200으로 바뀌게 되는 것이다.
또한 4바이트(32비트 기준)의 공간을 차지하는 포인터와 달리 레퍼런스는 특별히 공간을 차지하지 않고, 말 그대로 원본 그대로가 매개변수로 넘어가는것같은 효과이다.
이 좋은걸 왜 1개월차 끝나는 시점에알려줬는지 잘 모르겠지만 아마도 포인터와 좀더 친해지길 바란거같다.
이로서 1개월차 포스팅을 모두 마친다.
'c언어' 카테고리의 다른 글
클래스의 특징과 기본적 사용방법 (생성자와 소멸자) (0) | 2023.02.10 |
---|---|
2개월차의 시작, 객체 지향 프로그래밍? (0) | 2023.02.10 |
파일 입출력 -파일 읽기 및 쓰기 (0) | 2023.02.09 |
파일입출력 (0) | 2023.02.07 |
동적 할당(신버전) + 메모리 관련 함수들 (0) | 2023.02.07 |