struct
是一种简单的数据结构,是把不同类型的数据聚合在一起的一种方式。
在 C 语言里,struct
数据结构具有内存连续性的特点,就是说一个结构体的所有字段在内存里存储位置是连续的。
struct RGB {
int r;
int g;
int b;
};
以上结构体的内存布局,r
, g
, b
三个字段的存储是连续的。
POD (Plain Old Data)数据类型都有内存连续性的特点,因为他们都是常规数据类型。
C++ 中的 struct
,当它具有 class
的特性时,就不再是 POD 类型。它的内存结构与 C 语言中的 struct
不再具有兼容性。
struct Point {
float x;
float y;
};
struct Size {
float width;
float height;
};
struct Rect {
Point origin;
Size size;
Rect(float x, float y, float w, float h):
origin({ x, y }),
size({ w, h }) {
}
Rect():
origin({}),
size({}) {
}
};
在以上三个结构体中,Rect
就不是 POD 类型了,因为这个时候它已经具有 class
的特性(实现了构造函数)。
这个时候 Rect
不能与 C 语言混合使用,在 C 语言源文件中,如果是值引用,那么接收到的 Rect
类型是错误的:
// xx.h
struct Rect {
Point origin;
Size size;
#ifdef __cplusplus
Rect(float x, float y, float w, float h):
origin({ x, y }),
size({ w, h }) {
}
Rect():
origin({}),
size({}) {
}
#endif
};
// xx.cpp
Rect RectMake(float x, float y, float w, float h) {
return Rect{ x, y, w, h };
}
// main.c
float RectGetMaxY(CGRect bounds) {
return bounds.origin.y + bounds.size.height;
}
// RectMake is from c++ source
Rect bounds = RectMake(0, 0, 80, 80);
RectGetMaxY(bounds);
以上代码中,使用了宏 __cplusplus
区分 C++ 和 C 编译环境,使得 C 源文件中引用 Rect
结构体不会报错。
但是 C 源文件中,调用 C++ 中的接口创建的 Rect
结构体实际上并不是 POD 数据类型。
这就导致了 C 源文件中的函数 RectGetMaxY
会接收到一个错误的数据类型,但是编译器不会给出任何警告信息!。
以上,在 C++ 中如果需要把 struct
类型暴露给 C 语言中使用,最佳的做法是保持 struct
始终是 POD 数据类型。