2010-05-02 1 views
10

는 동일한 데이터를 의미하지만, 이런 다른 형태 가지고캐스팅 방법 C의 메모리 크기가 같으면 C struct를 다른 struct 유형으로 그냥 씁니까? I 2 매트릭스 구조체가

// Matrix type 1. 
typedef float Scalar; 
typedef struct { Scalar e[4]; } Vector; 
typedef struct { Vector e[4]; } Matrix; 

// Matrix type 2 (you may know this if you're iPhone developer) 
// Defines CGFloat as float for simple description. 
typedef float CGFloat; 
struct CATransform3D 
    { 
    CGFloat m11, m12, m13, m14; 
    CGFloat m21, m22, m23, m24; 
    CGFloat m31, m32, m33, m34; 
    CGFloat m41, m42, m43, m44; 
}; 
typedef struct CATransform3D CATransform3D; 

그들의 메모리 크기가 같은지를. 그래서 포인터를 조작하거나 복사하지 않고 이러한 유형을 변환하는 방법이 있다고 생각합니다.

// Implemented in external lib. 
CATransform3D CATransform3DMakeScale (CGFloat sx, CGFloat sy, CGFloat sz); 
Matrix m = (Matrix)CATransform3DMakeScale (1, 2, 3); 

이 방법이 가능합니까? 현재 컴파일러는 "오류 : 비 스칼라 유형 요청 변환"메시지를 인쇄합니다.

답변

16

아마 가장 좋은 해결책은 두 구조체를 결합으로 결합하는 것입니다. 동일한 데이터를 두 가지 다른 방식으로 해석하려는 경우 분명한 선택입니다. 대안은 포인터 캐스트를 사용하는 것입니다. 그러나 이것은 추한 것이고, 앨리어싱 규칙을 깨고, 그렇지 않으면 컴파일러가보고 할 수있는 오류를 숨길 수 있습니다.

typedef float Scalar; 
typedef struct { Scalar e[4]; } Vector; 
typedef struct { Vector e[4]; } Matrix; 

struct CATransform3D 
{ 
    CGFloat m11, m12, m13, m14; 
    CGFloat m21, m22, m23, m24; 
    CGFloat m31, m32, m33, m34; 
    CGFloat m41, m42, m43, m44; 
}; 
typedef struct CATransform3D CATransform3D; 

typedef union 
{ 
    CATransform3D t; 
    Matrix m; 
} UMatrix; 

CATransform3D CATransform3DMakeScale (CGFloat sx, CGFloat sy, CGFloat sz); 
UMatrix um; 
um.t = CATransform3DMakeScale (1, 2, 3); 
// 
// now you can just use um.m when you need to refer to the Matrix type... 
// 
+1

브릴리언트. 그러나 제 의견에는 일종의 프록시 변수가 필요합니다. 복사를하지 않습니까? – Eonil

+0

아니요 - 공용체를 typedef로 정의하십시오. 위의 예를 참조하십시오. –

+1

노조가 가장 좋습니다. 가장 안전하고 간단한 변환으로 오버 헤드가 없습니다. – Puppy

1

글쎄, 당신은 다음과 같이 CATransform3DMakeScale를 선언 할 수 :

Matrix CATransform3DMakeScale (CGFloat sx, CGFloat sy, CGFloat sz); 

C는 감속 원래의 라이브러리를 일치하는지 확인하기 위해 입력 - 확인하지 않습니다. 메모리 레이아웃이 같으면 작동합니다. 그러나 코딩 방법이 좋지 않으므로 작업을 정당화하는 긴 의견을 포함해야합니다. ;-)

그렇지 않으면 포인터를 사용하거나 데이터를 복사해야합니다. 그러면 작동합니다.

CATransform3D m3d = CATransform3DMakeScale (1, 2, 3); 
Matrix m; 
memcpy(&m, &m3d, sizeof m); 

발견 한대로 구조를 직접 캐스팅 할 수 없습니다. 또한이 작업을 수행 할 수 없습니다

Matrix m = *(Matrix*) &CATransform3DMakeScale (1, 2, 3); 

C는 당신이 L 값에 & 연산자를 사용할 수 있기 때문이다.

+1

이것은 포인터 캐스트를 통한'타입 punning '입니다 - 앨리어싱 규칙을 깨고 알맞은 컴파일러로 경고를 생성해야합니다. 참조 : http://en.wikipedia.org/wiki/Type_punning. 노조 트릭 또한 엄격히 UB이지만 일반적으로 포인터 캐스트 방법보다 안전하다고 간주됩니다. –

+1

@ Paul R : 좋은 지적입니다. 내 대답을 업데이트했습니다. –