C 和 C++ 中的结构体(struct)有和不同?

Jun 30, 2022 • 预计阅读时间 2 分钟

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 数据类型。

CC++
版权声明:如果转发请带上本文链接和注明来源。

lvv.me

iOS/macOS Developer

Swift 中的字符串插值

SwiftUI 学习资源