为什么 Linux / Android 系统里全是 struct + 函数指针?—— 一篇讲透 C 语言如何实现面向对象(OOP)

一、一个让我困惑很久的问题

刚学 Java / Android 时,

我一直觉得:

java 复制代码
class Dog {
    void run(){}
}

这种写法很自然。

因为:

  • 数据和行为放在一起
  • 有封装
  • 有继承
  • 有多态

这就是标准 OOP(面向对象)。


但后来开始接触:

  • Linux
  • 驱动
  • JNI
  • Android HAL
  • C/C++

我突然发现:

系统层代码里根本没有 class。

取而代之的是:

cpp 复制代码
struct xxx
void (*xxx)(void)

甚至大量代码长这样:

复制代码
device->ops->open();

我当时特别懵:

"这不是 C 语言吗?"

"怎么写得像 Java/C++ 一样?"

后来才真正理解:


本质上:

C 语言虽然没有 OOP 语法,

但完全可以实现 OOP 思想。

而 Linux / Android 系统层,

本质上就是:"用 C 写面向对象"。


二、C 为什么需要"面向对象"?

C 本身是过程式语言。

它没有:

  • class
  • private
  • inheritance
  • virtual
  • interface

但问题是:


大型系统一定需要:

能力 为什么需要
封装 隐藏实现细节
多态 统一接口
继承 代码复用
抽象 降低耦合

否则:

  • 驱动会乱
  • 模块无法扩展
  • 系统无法维护

所以: 工程师开始自己"模拟 OOP"。

核心思想就是:

  • struct 管状态
  • 函数管行为
  • 函数指针做动态分发

于是: C 开始"长得像 C++"。


三、C语言如何实现 OOP 三件套


1. struct = 对象(封装)

Java:

java 复制代码
class Led {
    int pin;

    void on(){}
}

C:

cpp 复制代码
typedef struct {
    int pin;
} Led;

void led_on(Led* led);

这里:

Java C
struct
对象成员 struct字段
成员方法 普通函数

进一步:

很多工程里会这样:

led.h

cpp 复制代码
typedef struct Led Led;

void led_on(Led* led);

led.c

cpp 复制代码
struct Led {
    int pin;
};

这叫:

不完整类型(Opaque Pointer)

作用:

  • 外部看不到成员
  • 只能通过接口操作

这其实就是:

C 版 private。


四、函数指针 = 多态(最核心)

普通写法:

cpp 复制代码
if(type == LED_RED){
    red_on();
}else{
    blue_on();
}

问题:

  • if/switch 巨多
  • 难扩展
  • 耦合严重

于是:C 引入函数指针。

函数指针写法:

定义操作表:

cpp 复制代码
typedef struct {
    void (*on)(void);
    void (*off)(void);
} LedOps;

不同对象绑定不同实现:

cpp 复制代码
LedOps red_ops = {
    .on = red_on,
    .off = red_off
};

LedOps blue_ops = {
    .on = blue_on,
    .off = blue_off
};

调用:

复制代码
led->ops->on();

看到这里是不是很眼熟?

因为:

这其实就是 C++ 虚函数底层思想。

本质:

复制代码
对象
    ↓
函数表(vtable)
    ↓
具体实现函数

也就是: "运行时动态分发"

这就是:C 语言的多态。


五、struct嵌套 = 继承

Java:

java 复制代码
class Animal {}

class Dog extends Animal {}

C 没有 extends。

于是:

cpp 复制代码
typedef struct {
    int id;
} Animal;

子类:

cpp 复制代码
typedef struct {
    Animal base;
    int age;
} Dog;

因为: struct 内存连续。

所以:

复制代码
Dog
=
Animal + 扩展字段

于是:

复制代码
Animal* a = (Animal*)&dog;

可以成立。

这就是:

C 语言版继承。


六、整个 Linux / Android 的底层世界

1. Linux 内核

经典:

复制代码
struct file_operations

里面全是函数指针:

复制代码
int (*open)(struct inode*, struct file*);
int (*read)(struct file*, char*, size_t);

本质:"驱动多态"

不同驱动:

  • open 不同
  • read 不同
  • write 不同

但调用接口统一。


2. Android HAL

Android 硬件抽象层:

复制代码
hw_module_t

本质也是:

复制代码
struct + function pointer

不同厂商:

  • 摄像头不同
  • 蓝牙不同
  • GPS不同

但 Framework 调用统一。


3. JNI

经典代码:

复制代码
(*env)->CallVoidMethod()

很多人第一次看到都懵。

其实:

JNIEnv 本质就是函数表。

也就是说:

复制代码
JNIEnv
=
C语言版虚函数表

JNI 本质就是:"C 的多态接口"

七、为什么系统层特别喜欢这种写法?

1. 内存完全可控

没有:

  • hidden object
  • RTTI
  • GC
  • 编译器隐藏逻辑

系统级开发非常重要。


2. ABI 稳定

C ABI 是跨平台事实标准。

所以:

  • Linux 内核
  • 驱动
  • HAL
  • OpenGL
  • FFmpeg

都大量使用 C 接口。


3. 性能稳定

函数表调用:

  • 成本明确
  • 内存布局固定
  • 无额外对象模型

特别适合:

  • 驱动
  • RTOS
  • Kernel

4. 更适合底层

系统层最怕:

复制代码
编译器偷偷帮你做了什么

而 C: 一切都摆在明面上。


八、一句话总结

struct 管状态

函数管行为

函数指针做多态

struct嵌套做继承

这就是:

C语言实现面向对象的核心思想。

九、扩展

这篇其实只是:《C语言对象模型》系列总纲。

后面准备继续深入几个系统层核心主题。


第一篇(世界观篇)

《为什么 Linux / Android 系统里全是 struct + 函数指针?》

也就是本文。

核心目标:

  • 建立 C 的对象模型认知
  • 理解系统层为什么大量使用 struct + 函数指针
  • 建立 Linux / Android / HAL / JNI 的统一认知

第二篇(多态篇)

《从函数指针到虚函数表:彻底理解 C 的多态》

这一篇会深入:

  • callback
  • function pointer
  • vtable
  • dispatch
  • runtime polymorphism

以及:

复制代码
device->ops->open();

背后到底发生了什么。

同时还会对比:

  • Java 多态
  • C++ virtual
  • C 函数表

彻底讲透:"虚函数表"的本质。


第三篇(JNI篇)

《JNIEnv 为什么是二级指针?本质就是函数表》

很多 Android 开发第一次看到:

复制代码
(*env)->CallVoidMethod()

都会懵。

这一篇会彻底讲透:

  • 为什么 JNI 是二级指针
  • 为什么 JNIEnv 像对象
  • 为什么 JNI 本质是函数表
  • Java 和 Native 是如何互相调用的

最终真正理解:JNI 本质就是 C 风格 OOP。


第四篇(内核篇)

《Linux 内核里的 container_of 到底是什么黑魔法?》

这一篇会进入 Linux 内核核心技巧。

深入:

  • offsetof
  • container_of
  • struct embedding
  • intrusive list
  • 面向对象内核设计

你会发现:

Linux 内核其实是"C语言对象模型"的终极形态。


十、最后

当你真正理解:

复制代码
struct + function pointer

之后,发现:

Linux

Android Framework

HAL

JNI

Driver


这些系统级代码,虽然写的是 C,但背后其实全是:"面向对象的思想"。

相关推荐
一拳一个娘娘腔3 小时前
入门必看:CVE-2026-31431(Copy Fail)漏洞全解析,700字节脚本拿下Root权限
linux·安全
沐言人生3 小时前
ReactNative 源码分析5——ReactActivity之启动RN应用
android·react native
leory3 小时前
synchronized和ReentrantLock的区别是什么?各自的使用场景?
android·面试
qinyia3 小时前
Rocky Linux 9 源码编译 Asterisk 20 + FreePBX 17 搭建小型呼叫中心
linux·运维·人工智能
MZ_ZXD0013 小时前
springboot音乐播放器系统-计算机毕业设计源码76317
java·c语言·c++·spring boot·python·flask·php
艾莉丝努力练剑3 小时前
【Linux网络】Linux 网络编程入门:TCP Socket 编程(上)
linux·运维·服务器·网络·tcp/ip·计算机网络
Konwledging3 小时前
Linux图形栈
linux
happytree0013 小时前
linux0.11 - bootsect.s 第三阶段(加载system)
linux
wgl6665203 小时前
ELF文件 && 链接与加载
linux·运维·服务器