typedef와 #defines


32

우리 모두는 확실히 사용한 typedef들과 #define한 번에 또는 다른이야. 오늘 저는 그들과 함께 일하면서 일을 고민하기 시작했습니다.

int다른 이름으로 데이터 유형 을 사용하려면 아래 두 가지 상황을 고려하십시오 .

typedef int MYINTEGER

#define MYINTEGER int

위의 상황과 마찬가지로 많은 상황에서 #define을 사용하여 일을 잘 수행 할 수 있으며 typedef를 사용하여 동일한 작업을 수행 할 수 있지만 동일한 방식은 상당히 다를 수 있습니다. #define은 typedef가 할 수없는 MACRO 작업도 수행 할 수 있습니다.

그것들을 사용하는 기본 이유는 다르지만 그들의 작업은 얼마나 다른가? 둘 다 사용할 수있는 경우 어느 것이 다른 것보다 선호되어야합니까? 또한 어떤 상황에서 다른 것보다 빠를 것이 보장됩니까? (예 : #define은 전 처리기 지시문이므로 모든 것이 컴파일 또는 런타임보다 일찍 완료됩니다).


8
#define을 사용하십시오. 코드를 작성할 때 알 수없는 속성 (OS / 컴파일러 등)을 기반으로하는 조건부 컴파일. 그렇지 않으면 언어 구성을 사용하십시오.
Martin York

답변:


67

typedef매크로가 특별히 필요한 이상한 이유가없는 한 A 가 일반적으로 선호됩니다.

매크로는 텍스트 대체를 수행하므로 코드의 의미에 상당한 폭력을 줄 수 있습니다. 예를 들면 다음과 같습니다.

#define MYINTEGER int

합법적으로 작성할 수 있습니다.

short MYINTEGER x = 42;

short MYINTEGER확장 되기 때문 short int입니다.

반면에 typedef를 사용하면 다음과 같습니다.

typedef int MYINTEGER:

name MYINTEGER은 키워드 "int"의 텍스트 대체가 아닌 type의 다른 이름입니다 int.

복잡한 유형 일수록 상황이 더욱 악화됩니다. 예를 들면 다음과 같습니다.

typedef char *char_ptr;
char_ptr a, b;
#define CHAR_PTR char*
CHAR_PTR c, d;

a, b, 및 c모든 포인터가 있지만 dA는 char마지막 줄로 확장하기 때문에 :

char* c, d;

어느 것이

char *c;
char d;

(포인터 타입의 타입 정의는 일반적으로 좋은 생각은 아니지만 요점을 보여줍니다.)

또 다른 이상한 경우 :

#define DWORD long
DWORD double x;     /* Huh? */

1
다시 비난하는 포인터! :) 그러한 매크로를 사용하는 것이 현명하지 않은 포인터 이외의 다른 예는 무엇입니까?
c0da

2
필자는 대신 매크로를 사용하지 typedef않았지만 다음과 같은 작업을 수행하는 매크로를 작성하는 올바른 방법은 인수를 사용하는 것 #define CHAR_PTR(x) char *x입니다. 이로 인해 컴파일러를 잘못 사용하면 최소한 kvetch가 발생합니다.
Blrfl

1
잊지 마세요 :const CHAR_PTR mutable_pointer_to_const_char; const char_ptr const_pointer_to_mutable_char;
Jon Purdy

3
또한 오류 메시지를 이해할 수 없도록 정의
Thomas Bonini

매크로를 잘못 사용하여 발생할 수있는 고통의 예 (매크로와 typedef는 직접 관련이 없지만) : github.com/Keith-S-Thompson/42
Keith Thompson

15

지금까지 매크로의 가장 큰 문제는 범위가 지정되지 않았다는 것입니다. 이것만으로 typedef의 사용을 보증합니다. 또한 의미 적으로 더 명확합니다. 코드를 읽는 사람이 정의를 볼 때 코드를 읽고 전체 매크로를 이해할 때까지 코드의 내용을 알 수 없습니다. typedef는 형식 이름이 정의 될 것을 독자에게 알려줍니다. (C ++에 대해 이야기하고 있다고 언급해야합니다. C에 대한 typedef 범위 지정에 대해서는 확실하지 않지만 비슷합니다.)


그러나 질문에 제공된 예제에서 보았 듯이 typedef와 #define은 같은 수의 단어를 사용합니다! 또한 매크로의이 3 개의 단어는 단어가 동일하지만 재 배열되기 때문에 혼동을 일으키지 않습니다. :)
c0da

2
예, 그러나 그것은 부족에 관한 것이 아닙니다. 매크로는 typedefing 외에도 다른 일을 할 수 있습니다. 그러나 개인적으로 나는 범위 지정이 가장 중요하다고 생각합니다.
Tamás Szelei

2
@ c0da-typedef에는 매크로를 사용하지 말고 typedef에는 typedef를 사용해야합니다. 매크로의 실제 효과는 다양한 응답으로 표시된 것처럼 매우 다를 수 있습니다.
Joris Timmermans

15

소스 코드는 주로 동료 개발자를 위해 작성되었습니다. 컴퓨터는 컴파일 된 버전을 사용합니다.

이 관점 typedef에서 #define그렇지 않은 의미가 있습니다.


6

Keith Thompson의 답변 은 매우 훌륭하며 범위 지정에 대한 Tamás Szelei의 추가 요점 과 함께 필요한 모든 배경을 제공해야합니다.

항상 매크로를 절망의 최후의 수단으로 생각해야합니다. 매크로로만 할 수있는 일이 있습니다. 그럼에도 불구하고, 정말로하고 싶다면 길고 열심히 생각해야합니다. 미묘하게 손상된 매크로로 인해 발생할 수있는 디버깅의 어려움은 상당하며 사전 처리 된 파일을 살펴볼 수 있습니다. C ++에서 문제의 범위에 대한 느낌을 얻으려면 한 번만 수행하는 것이 좋습니다. 전처리 된 파일의 크기 만 눈에 띄는 것일 수 있습니다.


5

#define은 이미 제공된 범위 및 텍스트 대체에 대한 모든 유효한 설명 외에도 typedef와 완전히 호환되지 않습니다! 즉, 함수 포인터의 경우에 관한 것입니다.

typedef void(*fptr_t)(void);

이것은 type fptr_t의 함수에 대한 포인터 인 type 을 선언합니다 void func(void).

이 유형은 매크로로 선언 할 수 없습니다. #define fptr_t void(*)(void)분명히 작동하지 않습니다. #define fptr_t(name) void(*name)(void)C 언어에서는 의미가 없으므로 생성자가없는 모호한 것을 작성해야합니다 .

#define으로 배열 포인터를 선언 할 수 없습니다. typedef int(*arr_ptr)[10];


C는 언급 할 가치가있는 유형 안전에 대한 언어 지원을 제공하지 않지만 typedef와 #define이 호환되지 않는 또 다른 경우는 의심스러운 유형 변환을 수행하는 경우입니다. typedef를 사용하는 경우 컴파일러 및 / 또는 정적 분석기 도구에서 이러한 변환에 대한 경고를 표시 할 수 있습니다.


1
함수와 배열 포인터의 조합이 더 좋습니다. char *(*(*foo())[])();( foo포인터를 반환하는 함수에 대한 포인터 배열에 대한 포인터를 반환하는 함수입니다 char).
John Bode 2012

4

작업을 수행하는 데 필요한 전원이 가장 적고 경고가 가장 많은 도구를 사용하십시오. #define은 전 처리기에서 평가되며 대부분 자체적으로 있습니다. typedef는 컴파일러에 의해 평가됩니다. 이름이 확인 하듯이 검사가 이루어지고 typedef는 유형 만 정의 할 수 있습니다. 따라서 귀하의 예에서 분명히 typedef로 이동하십시오.


2

define에 대한 일반적인 논쟁 외에도 Macros를 사용하여이 함수를 어떻게 작성할 것입니까?

template <typename IterType>
typename IterType::value_type Sum(
    const IterType& begin, 
    const IterType& end, 
    const IterType::value_type& initialValue)
{
    typename IterType::value_type result = initialValue;
    for (IterType i = begin; i != end; ++i)
        result += i;

    return result;
}

....

vector<int> values;
int sum = Sum(values.begin(), values.end(), 0);

이것은 명백한 예이지만, 그 함수는 더하기를 구현하는 형식의 순방향 반복 가능한 시퀀스를 합할 수 있습니다 *. 이와 같이 사용 된 Typedef는 Generic Programming 의 중요한 요소입니다 .

* 나는 이것을 여기에 썼다. 나는 그것을 독자를위한 운동으로 컴파일했다 :-)

편집하다:

이 답변은 많은 혼란을 일으키는 것처럼 보이므로 더 자세히 설명하겠습니다. STL 벡터의 정의를 살펴보면 다음과 비슷한 것을 볼 수 있습니다.

template <typename ValueType, typename AllocatorType>
class vector
{
public:
    typedef ValueType value_type;
...
}

표준 컨테이너 내에서 typedef를 사용하면 (위에서 만든 것과 같은) 일반 함수가 이러한 유형을 참조 할 수 있습니다. 함수 "합계"는 용기 (유형에 템플 레이팅 std::vector<int>되지 않은 용기 내에 유지 된 입력 (상) int). typedef가 없으면 해당 내부 유형을 참조 할 수 없습니다.

따라서 typedef는 Modern C ++의 중심이며 매크로에서는 불가능합니다.


이 질문은 typedef매크로 대 인라인 함수가 아니라 매크로 대 에 대해 질문했습니다 .
벤 Voigt

물론 이것은 typedefs에서만 가능합니다 ... value_type입니다.
Chris Pitman

이것은 typedef가 아니며 템플릿 프로그래밍입니다. 함수 나 함수는 형식에 관계없이 유형이 아닙니다.

@Lundin 자세한 내용을 추가했습니다. Sum 함수는 표준 컨테이너가 typedef를 사용하여 템플릿 형식을 노출하기 때문에 가능합니다. 나는 하지 합계가 형식 정의라고 말하고. std :: vector <T> :: value_type 이 typedef 라고 말하고 있습니다. 표준 라이브러리 구현의 소스를 확인하여 확인하십시오.
Chris Pitman

충분합니다. 두 번째 스 니펫 만 게시하는 것이 좋을 것입니다.

1

typedefC ++ 철학에 부합 : 컴파일 시간에 가능한 모든 확인 / 어설 션. #define컴파일러에 많은 의미를 숨기는 전 처리기 트릭입니다. 코드 정확성 이상의 컴파일 성능에 대해 걱정하지 않아도됩니다.

새 유형을 만들면 프로그램 도메인이 조작하는 새로운 "사물"을 정의하게됩니다. 따라서이 "사물"을 사용하여 함수와 클래스를 구성 할 수 있으며 컴파일러를 사용하여 정적 검사를 수행 할 수 있습니다. 어쨌든 C ++은 C와 호환 int되므로 경고를 생성하지 않는 int 기반 유형 간에 많은 암시 적 변환이 있습니다. 따라서이 경우 정적 검사 기능을 최대한 활용할 수 없습니다. 그러나, 당신은 당신을 대체 할 수 typedefenum암시 적 변환을 찾을 수 있습니다. 예 : 당신이 한 경우 typedef int Age;, 다음으로 대체 할 수있는 enum Age { };당신이 사이의 암시 적 변환에 의해 오류의 모든 종류를 얻을 것이다 Age하고 int.

또 다른 것은 : typedef안에있을 수 있습니다 namespace.


1

타입 정의 대신에 정의를 사용하는 것은 또 다른 중요한 측면, 즉 유형 특성의 개념에서 문제가됩니다. 특정 유형 정의를 정의하는 다양한 클래스 (표준 컨테이너 생각)를 고려하십시오. typedef를 참조하여 일반 코드를 작성할 수 있습니다. 예를 들면 다음과 같은 일반적인 컨테이너 요구 사항 (c ++ 표준 23.2.1 [container.requirements.general])이 있습니다.

X::value_type
X::reference
X::difference_type
X::size_type

이 모든 것은 범위가 없기 때문에 매크로를 사용하여 일반적인 방식으로 표현할 수 없습니다.


1

디버거에서 이것의 의미를 잊지 마십시오. 일부 디버거는 #define을 잘 처리하지 못합니다. 사용하는 디버거에서 모두 놀아보십시오. 그것을 쓰는 것보다 그것을 읽는 데 더 많은 시간을 소비한다는 것을 기억하십시오.


-2

"#define"은 작성한 내용을 대체하고 typedef는 유형을 생성합니다. 따라서 사용자 정의 유형을 원하면 typedef를 사용하십시오. 매크로가 필요한 경우 define을 사용하십시오.


나는 투표를 거부하고 의견을 쓰지 않는 사람들을 좋아합니다.
이니 우스
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.