Typedef,Pragma Once 뽀개기
by luis lee
- typedef 의 사용법
- #pragma once 에 대한 고찰 - 그런데 #pragma once는 치명적인 약점이 있다.
- ifndef 를 이용하는것과 비교해봤을때 - 결론적으로
- typedef 와 progma once 의 결론
typedef 의 사용법
typedef struct Vec3 { int x,y,z; } Vec3;
위의 사용법은 Vec3라는 struct 를 만들고 이에 대한 struct Vec3 의 타입을 Vec3로 정의한다는 뜻이다. 만약 이렇게 typedef를 하지 않았다면 Vec3 struct 인스턴스를 만들때마다 우리는
struct Vec3 myVec3;
와 같이 선언해야하지만 typedef를 이용하면
Vec3 myVec3;
로 선언이 가능해 진다.
typedef std::vector< int,std::vector<int,int> > studentID_List;
일반적으로 typedef를 이용해서 엄청나게 긴 type을 studentID_list
처럼 간단한 keyword로 정의를 내릴 수 있다.
따라서 자신의 프로젝트에서 위와 같이 엄청 길어지는 type을 자주 사용해야 한다면 typedef를 이용해서 코드를 간단하게 만들 수 있다.
typedef int array[10];
int main(){
array A;
for(int i = 9; i ; i--)
{
A[i] = i;
}
for(int i : A)
{
std::cout<< i <<" -> "<< A[i] <<std::endl;
}
}
위의 코드 처럼 typedef를 이용해 배열을 나타낼 수 도 있다.
typedef int (*functor)(int,int) ;
int add(int a, int b)
{
return a+b;
}
functor Add_function = nullptr;
Add_function = &add;
std::cout<<Add_function(2,3)<<std::endl;
조금더 응용해서 함수 포인터를 typedef를 이용해 정의할 수 있다.
#pragma once 에 대한 고찰
#pragma once
라는 전처리기는 들어본 사람도 있을 것이다. 이것은 우리가 만약
- main.c
- a.h
와 같이 main파일에 main함수가 있고 source.h라는 헤더가 main에 inlcude 되었다고 가정하자.
이와 같은 경우에는 큰 문제없이 컴파일을 진행 할 수 있다.
그런데 파일간의 구조가 점점 더 복잡해지는경우, 즉 다음과 같은경우는 어떻게될까?
- main.c
- a.h
- b.h
- b.h
- c.h
- c.h
- a.h
이렇게 파일의 구조가 있다고 하자. 이 관계는 main.c는 a,b,c 헤더파일을 모두 include하고 있으며 a.h와 b.h는 각각 b.h와 c.h를 include 하고있다.
이렇게 프로젝트가 복잡해져서 main에서 a,b,c 헤더가 모두 필요하며 a,b 헤더에서는 b 와 c의 헤더파일이 필요해서 꼬여버렷다고 치자.
그런 경우에 컴파일러 입장에서는 include가 어쨋든 해당 위치에 파일을 복붙해버리는 것이기 때문에 b.h 와 c.h 헤더에 있는 함수나 변수들이 중복이 되어버린다. 즉, 헤더가 중복되어서 include 되어버리는 경우에 컴파일러 에러로 이미 정의되어있는 변수, 함수 라는 에러코드를 뱉어내게 된다. 따라서
우리는 컴파일러에게 이미 인클루드 되어있는 헤더는 더이상 include하지 말라는 명령을 내려야 되는데 이게 바로 #pragma once 라는 명령어 이다.
즉, pragma once를 이용하면 프로젝트가 복잡해졌을때 여러번 include된 헤더에 대한 처리가 쉬워진다.
pragma once 이외에도
#ifndef __A_H__
#define __A_H__
//header file content
...
//
#endif
// nothing
와 같은 매크로를 사용하여 중복 define에 대한 에러를 잡아낼 수 도 있다. 이 방법은 이미 __A_H__
가 이미 정의가 되어있는 경우(ifndef
) #endif
로 점프하며 아니라면 __A_H__
를 정의한다는 뜻이다.
즉, 한번이라도 include가 되었다면 __A_H__
가 정의가 되어있기 때문에 include 하지 않게되는 것이다.
즉 두가지 방법으로 중복 선언에 대한 에러를 잡을 수 있다.
- pragma once
- ifndef
그런데 #pragma once는 치명적인 약점이 있다.
StackOverFlow 에서 논쟁이 있었는데, pragma once를 이용하면
#ifndef 를 이용하는것과 비교해봤을때
특정 헤더파일이 이미 인클루드 되었다면 아얘 확인자체를 하지 않기 때문에 성능면에서 더 좋을 수 있다고 한다. 하지만 고칠수없는 버그가 있다고 한다.
우리가 헤더파일을 쓰는데 서로 다른 폴더에 존재하며 이름이 같다고 해보자. 예를들면 A_folder/a.h 와 B_folder/a.h , 이렇게 들어있다. 이 경우 pragma once를 이용하게 되면
컴파일러가 두 헤더가 같은지 다른지 구분하지 못하기 때문에 치명적인 오류를 뱉어낼 수 있는것이다.
따라서 필자가 생각하기에도 pragma once가 사용적인 측면이나 성능면에서 좋다고 할 수 있지만 치명적인 실수에 의한 오류를 잡기 힘들다는 단점이 있기때문에
ifndef를 사용하는 습관을 익히는게 좋을 듯 하다.
결론적으로
- pragma once는 편리하고 성능도 ifndef보다 좋다
- pragma once는 고치기 힘든 버그를 생성할 수 도 있다는 의견이 많다.
- 따라서 pragma once보다는 ifndef를 이용해서 헤더를 관리하는게 더 좋을 것 같다.
typedef 와 progma once 의 결론
- typedef
- 타입이 너무 길때 사용하면 코드 길이를 줄일 수 있음.
- 함수포인터, 배열에도 사용이 가능함.
- struct를 선언할 때 같이 typedef를 사용하면 struct 인스턴스를 만들때 struct 키워드를 안쓸 수 있음.
- pragma once
- 헤더파일에 대한 include 시 중복 에러를 없앨 수 있음.
- ifndef 보다 사용이 편하고 최적화 적인 측면에서도 좋음
- 같은 파일명을 가지고 path만 다른 헤더파일의 경우 치명적인 오류가 발생.
- 여러 논쟁이 있을 수 있지만 필자는 pragma once 보다는 ifndef를 사용하는 것이 안전하기 때문에 좋다고 판단함.
Subscribe via RSS