C의 구조 확장

Aug 21 2020

다음과 같이 정의 된 2 개의 구조가 있다고 가정합니다.

typedef struct {
   T x;
   T y;
} A;

typedef struct {
   A a;
   T z;
} B;

구조 B에 대한 포인터를 구조 A에 대한 포인터로 취급 할 수 있습니까?

실제로 다음은 신뢰할 수있는 / 표준 / 이식 / 컴파일러 불변입니다.

B b = {{1,2},3};
A * a = &b;

print(a->x);
print(a->y);

답변

3 Lundin Aug 21 2020 at 08:19

C17 6.7.2.1은 다음과 같이 설명합니다 (강조 내) :

구조 객체 내에서 비트 필드가 아닌 멤버와 비트 필드가있는 단위에는 선언 된 순서대로 증가하는 주소가 있습니다. 적절하게 변환 된 구조체 객체에 대한 포인터는 초기 멤버 (또는 해당 멤버가 비트 필드 인 경우 해당 멤버가 상주하는 단위)를 가리키고 그 반대의 경우도 마찬가지 입니다.

즉, B b개체에 대한 포인터를 첫 번째 멤버의 형식으로 "적절하게 변환"해야합니다 . 이 변환은 암시 적으로 발생하지 않으며 명시 적 캐스트를 통해 수행해야합니다.

A * a = (A*)&b;

그렇게하는 것은 위에 인용 된 부분에 따라 잘 정의되고 안전합니다.

마찬가지로 컴파일러는에 대한 포인터 A와에 대한 포인터가 B별칭 을 사용 하지 않는다고 가정 할 수 없습니다. 유효 유형 6.5.7 ( "엄격한 별칭 지정") 규칙은이 경우에 예외를 제공합니다.

객체는 다음 유형 중 하나를 가진 lvalue 표현식에 의해서만 액세스되는 저장된 값을 가져야합니다.
...

  • 멤버 중 앞서 언급 한 유형 중 하나를 포함하는 집계 또는 공용체 유형

예를 들어, 최적화 중에 함수를 호출하는 컴파일러 void func (B* b)extern A a;다른 번역 단위에 정의 된 외부 계보 변수 가 함수에 의해 변경되지 않았다고 가정 할 수 없습니다.