최근 한 프로젝트로 인해 C언어 라이브러리를 델파이로 포팅할 일이 있었다.
대부분 구글링을 통해서 쉽게 변환할 수 있었는데 익명 공용체의 포팅에서 쉽게 알기 어려웠던 점이 있어 포스팅으로 남긴다.
먼저 구조체는 아래와 같이 사용된다.
C Style |
Delphi Style |
struct MyStruct { int a; char b; double c; }
|
MyStruct = record
a:integer;
b:char;
c:double;
end;
|
그리고 공용체는 아래와 같이 사용된다.
C Style | Delphi Style |
struct MyStruct { union { int a; char b; double c; } u; }
| MyStruct = record case Integer of
0: (a:integer);
1: (b:char);
2: (c:double);
end;
|
위와 같이 C에서 델파이로의 변환이 어렵지 않게 이뤄질 수 있는데 문제는 다음의 코드에서 발생했다.
#ifdef __GNUC__
#define PACKED( __Declaration__ ) __Declaration__ __attribute__((packed))
#else
#define PACKED( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) )
#endif
PACKED(
typedef struct param_union {
union {
float param_float;
int32_t param_int32;
uint32_t param_uint32;
int16_t param_int16;
uint16_t param_uint16;
int8_t param_int8;
uint8_t param_uint8;
uint8_t bytes[4];
}; // 익명 공용체
uint8_t type; // 공용체 이후 unsigned 8-bit int
}) param_union_t;
익명이 아니라면 공용체 레코드를 별도로 만들어서 아래와 같이 해결할 수 있지만
union_t = packed record
case Integer of
0: (param_float:single);
1: (param_int32:Int32);
2: (param_uint32:UInt32);
...
...
end;
param_union_t = packed record
u: union_t;
UInt8 type;
end;
익명 구조체이므로 어떻게 해결해야할지 Stack Overflow에 질문을 했었다.
(link: https://stackoverflow.com/questions/54613312/how-do-i-convert-a-c-union-to-delphi )
문의 결과 익명 공용체 이후에 기술되는 변수들은 가장 사이즈가 큰 case 뒤에 같이 서술하면 된단다.
동일한 byte 크기의 case가 여럿이면 그중 아무곳에나 서술하면 된다고 한다.
param_union_t = packed record
case Integer of
0: (param_float: Single);
1: (param_int32: Int32);
2: (param_uint32: UInt32;
&type: UInt8);
...
...
end;