C ++에서 익명 구조체를 허용하지 않는 이유는 무엇입니까?


92

일부 C ++ 컴파일러는 표준 C ++에 대한 확장으로 익명 공용체 및 구조체를 허용합니다. 때때로 매우 도움이되는 약간의 통 사적 설탕입니다.

이것이 표준의 일부가되는 것을 막는 근거는 무엇입니까? 기술적 인 장애물이 있습니까? 철학적입니까? 아니면 정당화 할 필요가 충분하지 않습니까?

다음은 제가 말하는 내용의 샘플입니다.

struct vector3 {
  union {
    struct {
      float x;
      float y;
      float z;
    };
    float v[3];
  };
};

내 컴파일러는 이것을 받아들이지 만 "nameless struct / union"이 C ++에 대한 비표준 확장 이라고 경고합니다 .


3
당신이 의미하는 바에 대해 약간의 혼란이 있습니다. 컴파일러 확장으로 인해 컴파일 만되는 코드의 예를 제공해 주시겠습니까?
Rob Kennedy

74
비슷하게 들리지만 크게 다른 두 가지 개념이 있습니다. 이름이 지정되지 않은 구조체익명 구조체 입니다. 첫 번째는 C ++에서 지원하는 것입니다 struct { int i; } a; a.i = 0;(유형에는 이름이 없습니다). 두 번째는 C ++에서 지원 하지 않는struct { int i; }; i = 0; 이 유형입니다 (유형에는 이름이 없으며 주변 범위로 이스케이프 됨). C ++는, 그러나, 하지 모두 이름이 익명 지원 조합을 .
Johannes Schaub-litb

이것은 다소 흥미로운 VMMLib 벡터 라이브러리처럼 보입니다. 문제는 유니온에 명명되지 않은 구조체가 포함되어 있다는 것이지만 확실하지 않습니다.
greyfade 2010

1
FWIW 그것은 "unnamed"가 아니라 "anonmyous"이며 litb가 말한 것처럼 공용체 지원됩니다. stackoverflow.com/q/14248044/560648
궤도의 밝기 경주

1
@AdrianMcCarthy : 괜찮습니다 (FSVO "fine"; 성가신 컴파일러는 비밀 스럽습니다).하지만 정확히 "unnamed"는 관련없는 표준 개념입니다.
궤도

답변:


50

다른 사람들이 지적했듯이 익명 공용체는 표준 C ++에서 허용되지만 익명 구조체는 허용되지 않습니다.

그 이유는 C는 익명 구조체를 지원하지만 익명 구조체 *는 지원하지 않기 때문입니다. 따라서 C ++는 호환성을 위해 전자를 지원하지만 호환성에 필요하지 않기 때문에 후자는 지원하지 않습니다.

또한 C ++의 익명 구조체는 많이 사용되지 않습니다. 당신이 보여 사용에 의해 중 하나라고 할 수있는 세 가지 수레가 포함 된 구조체가하는 .v[i], 또는 .x, .y그리고 .z++ 나 C에서 정의되지 않은 동작의 결과를 믿는다. C ++에서는 공용체의 한 멤버 (예 :)에 쓰고 .v[1]다른 멤버 (예 :)에서 읽을 수 없습니다 .y. 이를 수행하는 코드는 드물지 않지만 실제로 잘 정의되어 있지는 않습니다.

사용자 정의 유형에 대한 C ++의 기능은 대체 솔루션을 제공합니다. 예를 들면 :

struct vector3 {
  float v[3];
  float &operator[] (int i) { return v[i]; }
  float &x() { return v[0]; }
  float &y() { return v[1]; }
  float &z() { return v[2]; }
};

* C11은 분명히 익명 구조체를 추가하므로 향후 C ++ 개정판에서 추가 할 수 있습니다.


2
+1 : 내 예제는 C ++의 정의되지 않은 동작에 의존합니다. 질문을 작성할 때 알지 못했던 것입니다.
Adrian McCarthy 2012 년

2
"C ++에서는 공용체의 한 멤버에 쓰고 [...] 다른 멤버에서 읽을 수 없습니다. "-해당 멤버가 표준 레이아웃 개체이고 고유 한 멤버의 공통 초기 시퀀스 를 공유 하지 않는 한 , 다시 쓰기 / 읽기 자신의 상기 공통 초기 시퀀스 내에서 회원을. 그 되어 허용 (즉 정의).
underscore_d

5
@underscore_d : 예, 유형이 공통 초기 시퀀스가있는 표준 레이아웃 인 경우. 그러나 C ++의 "공통 초기 시퀀스"규칙은 공통 초기 시퀀스가 구조체 사이에만있을 수 있다고 명시하기 때문에 구조체는 이런 방식으로 배열 과 별칭을 사용할 수 없습니다. . 배열은 언급되지 않았으므로 이와 같이 별칭을 지정할 수 없습니다.
Nicol Bolas 2016 년

@NicolBolas 오, 하하-저를 믿으십시오-저는 배열과 다른 프리미티브가이 허용치에 포함되기를 여러 번 바랬습니다! 그러나 나는 그것에 대한 가능한 실질적인 한계에 대해 많이 생각하지 않았으므로 아마도 현재 보이는 것처럼 간단하지 않을 것입니다. 내 의견은 더 일반적이지만 여기에 배열이 포함되어 있다고 생각했음을 생략하여 암시했을 수 있으므로 추가해 주셔서 감사합니다.
underscore_d

"그 이유는 C가 익명 구조체를 지원하지 않고 익명 공용체를 지원하기 때문입니다."-아니요. 각주에서 C99 또는 이전 버전에 대해 이야기하고 있음을 분명히 알 수 있습니다. "익명 공용체"라는 용어는 C99 표준의 어디에도 나타나지 않습니다. GCC는 진단 (-std = c99 -pedantic 옵션 사용)에서 "ISO C99는 명명되지 않은 구조체 / 조합을 지원하지 않습니다"라고 주장합니다. 표준은 명명되지 않은 비트 필드 외에 명명되지 않은 멤버에 대해서는 언급하지 않습니다. struct-declarations가 선언인지 확실하지 않지만, 그렇다면 익명 공용체는 6.7p2 당 제약 조건 위반이며 기껏해야 정의되지 않습니다.

21

나는 vector3단지 사용 하여 선언을 정리할 수 있습니다 .union

union vector3 {
  struct { float x, y, z; } ;
  float v[3] ;
} ;

물론 익명 구조 MSVC 확장 이었습니다. 그러나 ISO C11은 지금 그것을 허용하고 gcc는 그것을 허용하며 Apple의 llvm 컴파일러도 허용합니다.

왜 C ++ 11이 아닌 C11입니까? 확실하지는 않지만 실제로 대부분 (gcc ++, MSVC ++ 및 Apple의 C ++ 컴파일러) C ++ 컴파일러가이를 지원합니다.


1
업데이트 된 정보는 +1. 내가 외부 구조체를 가진 이유는 "실제 코드"에도 메소드가 있기 때문입니다.
Adrian McCarthy

공용체로 할 수없는 유일한 것은 정적 데이터 멤버가 있거나 상속을 사용하는 것 입니다.
bobobobo

2
감사. 새로운 공용체는 구조체 나 클래스처럼 사용할 수 없습니다.
Adrian McCarthy

나는 Sun studio가 기본적으로 C ++ 11 이전의 익명 구조체를 지원하지 않았다는 것을 알고 있습니다. 크로스 플랫폼 코드를 작성하고 컴파일러가 C + 11로 업그레이드되지 않은 경우 익명 구조체를 사용하지 마십시오.
irsis

6

당신이 무슨 뜻인지 확실하지. C ++ 사양의 섹션 9.5, 조항 2 :

형태의 결합

union { member-specification } ;

익명의 조합이라고합니다. 명명되지 않은 유형의 명명되지 않은 개체를 정의합니다.

다음과 같이 할 수도 있습니다.

void foo()
{
  typedef
  struct { // unnamed, is that what you mean by anonymous?
    int a;
    char b;
  } MyStructType; // this is more of a "C" style, but valid C++ nonetheless

  struct { // an anonymous struct, not even typedef'd
    double x;
    double y;
  } point = { 1.0, 3.4 };
}

항상별로 유용하지는 않지만 ... 때로는 불쾌한 매크로 정의에 유용합니다.


11
-1은 익명 구조체를 정의하고 있기 때문입니다. 질문에 대한 위의 주석을 참조하십시오-익명의 구조체가 아닌 이름없는 구조체를 정의하고 있습니다.
Johannes Schaub-litb

1

공용체는 익명 일 수 있습니다. 표준, 9.5 단락 2를 참조하십시오.

익명의 구조체 또는 클래스가 어떤 목적을 충족한다고 생각합니까? 표준에없는 이유를 추측하기 전에 그 이유를 알고 싶습니다. 익명 구조체에 대한 용도는 보이지 않습니다.


1

편집, 주석 및이 MSDN 문서 : Anonymous Structures를 기반으로 추측 할 수 있습니다. 캡슐화 개념에 맞지 않습니다. 클래스의 멤버가 단순히 멤버를 하나만 추가하는 것 이상으로 클래스 네임 스페이스를 엉망으로 만들기를 기대하지는 않습니다. 또한 익명 구조를 변경하면 허가없이 수업에 영향을 미칠 수 있습니다.


1
익명 구조체 / 유니온이 생성되는 방식 (매크로를 제외하고는 숨길 수없는 특수한 인라인 구문)으로 인해 사용중인 일부 멤버가 익명 멤버라는 사실에 놀랄 수 없습니다. 그래서 나는이 추론이 말이되지 않는다고 생각합니다. 실제 이유는 익명 공용체 C 호환성을 위해서만 C ++에서 지원되기 때문입니다. C는 익명 구조체 (C11까지)를 지원하지 않으므로 C ++도 지원하지 않습니다.
bames53

1

귀하의 코드

union {
  struct {
    float x;
    float y;
    float z;
  };
  float v[3];
};

처럼

union Foo {
   int;
   float v[3];
};

확실히 유효하지 않습니다 (C99 이전).

그 이유는 아마도 구문 분석을 단순화하기위한 것입니다 (C에서).이 경우 구조체 / 유니온 본문에 다음과 같은 "선언자 문"만 있는지 확인하기 만하면됩니다.

Type field;

즉, gcc 및 "다른 컴파일러" 는 이름없는 필드를 확장으로 지원합니다.

편집 : 이제 익명 구조체가 C11 (§6.7.2.1 / 13)에서 공식적으로 지원됩니다.


5
파싱 ​​관점에서 볼 union { ... }struct { ... }. 전자는 유효하지만 후자는 유효하지 않습니다.
Johannes Schaub-litb

3
C ++가 일반적으로 파싱하기가 얼마나 어려운지를 감안할 때, 표준이 단지 파싱을 단순화하기 위해 허용되지 않는 명명되지 않은 구조체와 공용체를 커밋 한 것인지 의심합니다.
Adrian McCarthy

@Adrian : 저는 C ++가 아니라 C라고 말했습니다. C ++는 C의 구문을 채택하고 확장합니다. 아마도 C ++의 작성자는 명명되지 않은 struct / union 멤버를 허용 할 필요가 없으므로 구문의 해당 부분을 엉망으로 만들지 않습니다.
kennytm 2010

@Adrian, 좋은 점은 애드리안, 난 항상 적 비얀의 관심과 승무원 것 "구현 너무 열심히"가 생각하지 않았다
bobobobo

C와 C ++는 모두 이름없는 공용체를 지원하므로 union { ... };유효하지 않은 주석은 올바르지 않습니다.
bames53
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.