C 和 C++ 虽然都支持结构体(struct),但由于语言范式的不同(C 是过程式,C++ 是面向对象),结构体的惯用法(idioms)存在显著差异 。下面从设计哲学、语法细节、内存布局、典型用法等角度,系统对比并总结 C 与 C++ 中结构体的惯用方法。
一、C 语言中结构体的惯用法
1. 核心目的:数据聚合 + 接口封装
C 没有类,结构体是组织复杂数据的主要手段,常配合函数指针模拟"对象行为"。
2. 典型惯用法
(1) 使用 typedef 简化声明
typedef struct {
int x, y;
} Point;
// 用法:Point p = {1, 2};
避免每次写
struct Point,提升可读性。
(2) 模拟"私有成员" + "方法"
通过不透明指针(Opaque Pointer)隐藏实现:
// point.h
typedef struct Point Point; // 不定义内容
Point* point_create(int x, int y);
void point_destroy(Point* p);
int point_get_x(const Point* p);
// point.c
struct Point {
int x, y;
};
Point* point_create(int x, int y) {
Point* p = malloc(sizeof(Point));
p->x = x; p->y = y;
return p;
}
// 用户无法直接访问 x/y,实现封装
(3) 柔性数组成员(FAM)处理变长数据
typedef struct {
size_t len;
char data[]; // C99+
} Buffer;
Buffer* buf = malloc(sizeof(Buffer) + 100);
(4) 函数指针实现"多态"或回调
typedef struct {
void (*print)(const void*);
void (*destroy)(void*);
} ObjectOps;
typedef struct {
ObjectOps* ops;
char name[32];
} MyObject;
Linux 内核大量使用此模式(如 file_operations)
(5) 内存对齐控制(嵌入式/协议解析)
#pragma pack(push, 1)
typedef struct {
uint8_t type;
uint32_t id;
} PacketHeader; // 禁止 padding,确保 5 字节
#pragma pack(pop)
二、C++ 中结构体的惯用法
1. 核心理念:struct ≈ class,只是默认 public
在 C++ 中,struct 和 class 唯一区别是默认访问权限 (struct 默认 public,class 默认 private)。因此,struct 常用于:
- 纯数据载体(POD / Trivial Types)
- 需要公开成员的轻量对象
- 模板元编程中的类型标签
2. 典型惯用法
(1) POD(Plain Old Data)结构体
用于与 C 兼容、序列化、内存映射等场景:
1struct Vec3 {
2 float x, y, z; // 所有成员 public,无虚函数,无自定义构造/析构
3};
4static_assert(std::is_trivial_v<Vec3>);
5static_assert(std::is_standard_layout_v<Vec3>);
可安全
memcpy、memset,适合网络/文件 I/O。
(2) 聚合初始化(Aggregate Initialization)
C++11+ 支持简洁初始化:
1struct Config {
2 int timeout;
3 bool enable_log;
4};
5
6Config cfg{30, true}; // 直接初始化
7Config cfg2{.timeout=60}; // C++20 支持 designated initializer
(3) 作为"值类型"使用(拷贝语义)
C++ 鼓励结构体具有值语义(value semantics):
1struct Point {
2 int x = 0, y = 0; // 默认成员初始化(C++11)
3
4 // 编译器自动生成拷贝构造、赋值、析构(Rule of Zero)
5};
6
7Point p1{1, 2};
8Point p2 = p1; // 安全深拷贝(若成员都是值类型)
(4) 与 STL 容器无缝配合
1std::vector<Point> points;
2std::sort(points.begin(), points.end(), [](auto& a, auto& b) {
3 return a.x < b.x;
4});
(5) 模板中的"标签类型"或"策略"
1struct FastMode {};
2struct SafeMode {};
3
4template<typename Mode>
5void process(Mode) {
6 if constexpr (std::is_same_v<Mode, FastMode>) {
7 // 快速路径
8 }
9}
(6) 继承与多态(虽少用,但合法)
1struct Shape {
2 virtual double area() const = 0;
3 virtual ~Shape() = default;
4};
5
6struct Circle : Shape {
7 double r;
8 double area() const override { return 3.14 * r * r; }
9};
尽管可用,但通常用
class表示这种"有行为"的类型
三、关键对比表

四、建议
C 语言:
- 用
typedef struct { ... } Name;简化类型名。 - 对外暴露接口时,使用不透明指针实现封装。
- 变长数据优先考虑柔性数组而非二级指针。
- 协议/硬件寄存器结构体务必控制对齐。
C++ 语言:
- 纯数据结构用
struct,有复杂行为/封装用class(风格约定)。 - 优先遵循 Rule of Zero:避免手动管理资源(让编译器生成)。
- 若需与 C 交互,确保结构体是 standard-layout / trivial。
- 利用
= default、= delete显式控制特殊成员函数。
五、混合开发注意事项(C/C++ 互操作)
若 C++ 代码需被 C 调用(如库开发):
// mylib.h
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
int id;
float value;
} DataRecord; // 必须是 POD
void process_record(DataRecord* r);
#ifdef __cplusplus
}
#endif
保结构体不含 C++ 特性(虚函数、引用、非 POD 成员)。
总结
- C 的 struct 是"数据容器",靠函数指针和命名约定模拟对象。
- C++ 的 struct 是"轻量 class",天然支持面向对象特性,但惯用于值类型。
- 柔性数组、不透明指针、内存对齐是 C 的特色技巧;
- 聚合初始化、Rule of Zero、POD 保证是 C++ 的现代用法。