답변:
C ++에서는 미묘한 차이 만 있습니다. C와의 차이로 차이를 만듭니다.
C 언어 표준 ( C89 §3.1.2.3 , C99 §6.2.3 및 C11 §6.2.3 )은 태그 식별자 ( struct
/ union
/ enum
) 및 일반 식별자 ( typedef
및 기타 식별자)를 포함하여 다양한 범주의 식별자에 대해 별도의 네임 스페이스를 요구합니다. .
방금 말한 경우 :
struct Foo { ... };
Foo x;
Foo
태그 네임 스페이스에만 정의되어 있으므로 컴파일러 오류가 발생 합니다.
다음과 같이 선언해야합니다.
struct Foo x;
를 참조하려고 Foo
할 때마다 항상로 호출해야합니다 struct Foo
. 이것은 짜증나게하기 때문에 다음을 추가 할 수 있습니다 typedef
.
struct Foo { ... };
typedef struct Foo Foo;
이제 struct Foo
(태그 네임 스페이스에서) 일반 Foo
(일반 식별자 네임 스페이스에서)은 모두 동일한 것을 참조 Foo
하며 struct
키워드 없이 유형의 객체를 자유롭게 선언 할 수 있습니다 .
구성 :
typedef struct Foo { ... } Foo;
선언의 약어 일뿐 typedef
입니다.
드디어,
typedef struct { ... } Foo;
익명 구조를 선언하고 typedef
이를 만듭니다 . 따라서이 구문을 사용하면 태그 네임 스페이스에 이름이없고 typedef 네임 스페이스에 이름 만 있습니다. 이것은 또한 앞으로 선언 될 수 없다는 것을 의미합니다. 정방향 선언을하려면 태그 네임 스페이스에 이름을 지정해야합니다 .
C ++ 에서 이름이 같은 이름을 가진 다른 선언에 의해 숨겨지지 않는 한 모든 struct
/ union
/ enum
/ class
선언은 암시 적으로 선언 된 것처럼 작동 typedef
합니다. 자세한 내용은 Michael Burr의 답변 을 참조하십시오.
에서 이 DDJ 문서 , 단 삭스는 당신이 당신의 구조체 typedef에하지 않으면 버그를 통해 크리프 수있는 하나 개의 작은 영역을 설명 (및 클래스를!)
원한다면 C ++이 모든 태그 이름에 대해 typedef를 생성한다고 상상할 수 있습니다.
typedef class string string;
불행히도 이것은 완전히 정확한 것은 아닙니다. 나는 그것이 그렇게 간단하기를 원하지만 그렇지 않습니다. C ++은 C와의 비 호환성을 도입하지 않으면 구조체, 공용체 또는 열거 형에 대해 이러한 typedef를 생성 할 수 없습니다.
예를 들어, C 프로그램이 status라는 이름의 함수와 구조체를 선언한다고 가정합니다.
int status(); struct status;
다시 말하지만, 이것은 나쁜 습관이지만 C입니다.이 프로그램에서 상태 자체는 기능을 나타냅니다. 구조체 상태는 유형을 나타냅니다.
C ++가 태그에 대해 typedef를 자동으로 생성 한 경우이 프로그램을 C ++로 컴파일하면 컴파일러는 다음을 생성합니다.
typedef struct status status;
불행히도이 유형 이름은 함수 이름과 충돌하고 프로그램은 컴파일되지 않습니다. 그렇기 때문에 C ++은 단순히 각 태그에 대한 typedef를 생성 할 수 없습니다.
C ++에서 태그는 typedef 이름과 동일하게 작동하지만 프로그램이 태그와 이름 및 범위가 동일한 객체, 함수 또는 열거자를 선언 할 수 있습니다. 이 경우 객체, 함수 또는 열거 자 이름이 태그 이름을 숨 깁니다. 프로그램은 태그 이름 앞에 키워드 class, struct, union 또는 enum (적절한 경우)을 사용하여 태그 이름 만 참조 할 수 있습니다. 이러한 키워드 중 하나와 태그로 구성되는 유형 이름은 정교한 유형 지정자입니다. 예를 들어, struct status 및 enum month는 정교한 유형 지정자입니다.
따라서 다음을 모두 포함하는 C 프로그램 :
int status(); struct status;
C ++로 컴파일 할 때 동일하게 동작합니다. 이름 상태만으로도 기능을 나타냅니다. 프로그램은 정교한 형식 지정자 구조체 상태를 사용해야 만 형식을 참조 할 수 있습니다.
그렇다면 어떻게 버그가 프로그램에 영향을 줄 수 있습니까? Listing 1 의 프로그램을 고려하자 . 이 프로그램은 기본 생성자와 foo 객체를 char const *로 변환하는 변환 연산자로 클래스 foo를 정의합니다. 표현식
p = foo();
main에서 foo 객체를 생성하고 변환 연산자를 적용해야합니다. 후속 출력문
cout << p << '\n';
클래스 foo를 표시해야하지만 그렇지 않습니다. 함수 foo를 표시합니다.
이 놀라운 결과는 프로그램이 Listing 2에 표시된 헤더 lib.h를 포함하기 때문에 발생한다 . 이 헤더는 foo라는 함수를 정의합니다. 함수 이름 foo는 클래스 이름 foo를 숨기므로 main에서 foo에 대한 참조는 클래스가 아니라 함수를 참조합니다. main은 다음과 같이 정교한 형식 지정자를 사용해야 만 클래스를 참조 할 수 있습니다.
p = class foo();
프로그램 전체에서 이러한 혼동을 피하는 방법은 클래스 이름 foo에 다음 typedef를 추가하는 것입니다.
typedef class foo foo;
클래스 정의 직전 또는 직후. 이 typedef는 형식 이름 foo와 함수 이름 foo (라이브러리에서) 사이에 컴파일 타임 오류를 유발하는 충돌을 일으 킵니다.
물론 이러한 typedef를 실제로 작성하는 사람은 아무도 없습니다. 많은 훈련이 필요합니다. Listing 1 의 오류와 같은 오류의 발생률은 매우 작기 때문에 많은 사람들이이 문제를 무시하지는 않는다. 그러나 소프트웨어 오류로 인해 신체 부상을 입을 수있는 경우 오류 가능성에 관계없이 typedef를 작성해야합니다.
왜 누군가가 클래스와 같은 범위에서 함수 또는 객체 이름을 가진 클래스 이름을 숨기고 싶어하는지 상상할 수 없습니다. C의 숨기기 규칙은 실수였으며 C ++의 클래스로 확장되어서는 안됩니다. 실제로 실수를 바로 잡을 수는 있지만 불필요한 프로그래밍 분야와 노력이 필요합니다.
Listing 1
및 Listing 2
링크가 끊어집니다. 보세요
한 가지 더 중요한 차이점은 다음과 같습니다. typedef
s 전달할 수 없습니다. 그래서에 대한 typedef
옵션을 수행해야합니다 #include
파일은을 포함하는 typedef
모든 것을 의미 #include
당신의이야 .h
또한 직접 필요 여부 등 여부를 해당 파일을 포함합니다. 더 큰 프로젝트에서 빌드 시간에 영향을 줄 수 있습니다.
이 없으면 파일 의 맨 typedef
앞에 포워드 선언을 추가하고 파일 의 구조체 정의 만 추가 할 수 있습니다 .struct Foo;
.h
#include
.cpp
이 인 차이가 있지만, 미묘한는. 이런 식으로보십시오 : struct Foo
새로운 유형을 소개합니다. 두 번째는 명명되지 않은 struct
유형에 대해 Foo (새 유형이 아님)라는 별칭을 만듭니다 .
7.1.3 typedef 지정자
1 [...]
typedef 지정자로 선언 된 이름은 typedef-name이됩니다. 선언의 범위 내에서 typedef-name은 구문 상 키워드와 동일하며 8 절에 설명 된 방식으로 식별자와 연관된 유형의 이름을 지정합니다. 따라서 typedef-name은 다른 유형의 동의어입니다. typedef-name 은 클래스 선언 (9.1) 또는 열거 선언과 같은 방식으로 새 유형을 도입 하지 않습니다.
8 typedef 선언이 명명되지 않은 클래스 (또는 열거 형)를 정의하는 경우 선언에 의해 해당 클래스 유형 (또는 열거 형)으로 선언 된 첫 번째 typedef-name은 링크 목적으로 만 클래스 유형 (또는 열거 형)을 나타내는 데 사용됩니다 ( 3.5). [ 예:
typedef struct { } *ps, S; // S is the class name for linkage purposes
따라서 typedef는 항상 다른 유형의 자리 표시 자 / 동의어로 사용됩니다.
typedef 구조체에는 정방향 선언을 사용할 수 없습니다.
구조체 자체는 익명 형식이므로 전달할 실제 이름이 없습니다.
typedef struct{
int one;
int two;
}myStruct;
이와 같은 선언은 작동하지 않습니다.
struct myStruct; //forward declaration fails
void blah(myStruct* pStruct);
//error C2371: 'myStruct' : redefinition; different basic types
myStruct
는 태그 네임 스페이스에 있고 typedef_ed myStruct
는 함수 이름, 로컬 변수 이름과 같은 다른 식별자가있는 일반 네임 스페이스에 있습니다. 따라서 충돌이 없어야합니다. 오류가 있다고 의심되면 내 코드를 보여줄 수 있습니다.
typedef
가진 앞으로 선언 만있을 때 typedef
명명되지 않은 구조를 참조하지 않는다는 것을 이해합니다 . 대신 forward 선언은 tag로 불완전한 구조를 선언합니다 myStruct
. 또한의 정의를 보지 않으면 ed 이름을 typedef
사용하는 함수 프로토 타입 typedef
이 적합하지 않습니다. 따라서 myStruct
타입을 나타 내기 위해 사용해야 할 때마다 전체 typedef를 포함시켜야합니다 . 내가 오해하면 저를 수정하십시오. 감사.
C ++에서 'typedef 구조체'와 'struct'의 중요한 차이점은 'typedef 구조체'에서 인라인 멤버 초기화가 작동하지 않는다는 것입니다.
// the 'x' in this struct will NOT be initialised to zero
typedef struct { int x = 0; } Foo;
// the 'x' in this struct WILL be initialised to zero
struct Foo { int x = 0; };
x
초기화됩니다. Coliru 온라인 IDE에서 테스트를 참조하십시오 (42로 초기화되었으므로 할당이 실제로 발생했다는 것이 0보다 분명합니다).
C ++에는 차이가 없지만 C에서는 명시 적으로 수행하지 않고 구조체 Foo의 인스턴스를 선언 할 수 있다고 생각합니다.
struct Foo bar;