Linux驱动开发理解指针与结构体

第一部分:指针到底是什么?

指针 = 一张"地址小纸条"

  • 普通变量:家里放了一把钥匙(值)。
  • 指针变量:手里拿着一张写着"钥匙放在哪"的纸条(地址)。

看下面这张图(最经典的指针解释):

图里关键点

  • var 变量放在地址 0x7ffa0757dd4,里面存着 10
  • ptr 是指针,它自己存的不是 10,而是 var 的地址 0x7ffa0757dd4
  • *ptr(解引用) = 顺着纸条找到钥匙,拿到 10

一句话总结

指针变量里存的是别人的内存地址 ,用 * 才能拿到真正的值。

第二部分:结构体是什么?

结构体 = 一个"文件袋",里面可以放不同类型的东西。

看下面这张图(结构体在内存里的真实样子):

图里说明

  • struct example 里有 char aint bchar c
  • 因为CPU喜欢"对齐"(一次读4字节),编译器会自动在中间加padding(填充)
  • 所以整个结构体占12字节,而不是6字节(这在内核驱动里非常重要!)

第三部分:指针 + 结构体 = Linux驱动里的"王炸"

最常用的是指向结构体的指针

看这张超级清晰的图:

图里解释

  • ptr 存的是整个结构体的起始地址(1080)
  • 通过 ptr->nameptr->roll 就能直接访问里面的字段
  • 这就是驱动里 struct my_device *dev = ... 的真实样子!

再看一张更直观的(指针指向结构体):

驱动里的实际例子

c 复制代码
struct my_device {
    int id;              // 设备编号
    char name[32];       // 设备名字
};

struct my_device dev;           // 普通结构体变量
struct my_device *p = &dev;     // 指针指向它(驱动里99%都用这种)

p->id = 1;                      // 等价于 (*p).id = 1

实例练习

Ubuntu 新建 understand_lab.c,复制下面代码运行:

c 复制代码
#include <stdio.h>

struct student {
    int id;
    char name[20];
};

int main() {
    struct student s = { .id = 100, .name = "Tesha" };
    struct student *p = &s;          // 指针指向结构体

    printf("直接访问:id=%d, name=%s\n", s.id, s.name);
    printf("通过指针访问:id=%d, name=%s\n", p->id, p->name);

    printf("结构体地址:%p\n", (void*)&s);
    printf("指针存的地址:%p\n", (void*)p);
    return 0;
}

编译运行:

bash 复制代码
gcc -Wall -g understand_lab.c -o understand_lab
./understand_lab

输出如下:

第四部分:C语言指针与结构体核心符号对比表(驱动开发专用版)

概念/符号 含义(白话解释) 适用对象 示例代码 内存本质(地址视角) 驱动开发注意点(避免Panic) 等价写法 / 口诀
普通变量 直接存放"值"(钥匙) 变量本体 int a = 42; 地址里存的是值本身 几乎不用(驱动里全是指针) -
指针变量 存放"地址纸条"(指向别人的地址) 任何类型 int *p = &a; 地址里存的是另一个变量的地址 必须先判断 if (!p),否则空指针Panic "纸条"
& (取地址) "给我这个变量的地址" 变量本体 p = &a;struct student *sp = &s; 返回变量的起始地址 只用于赋值给指针变量 "拿纸条"
*** ** (星号) ①声明指针 ②解引用(打开纸条看内容) ①声明时 ②使用时 int *p; *p = 100; ①声明类型 ②顺着地址取值/改值 忘记解引用或多解引用会导致野指针 "*声明=指针,*使用=打开看"
. (点) 访问结构体本体的成员 结构体变量(非指针) struct student s; s.id = 100; 结构体起始地址 + 成员偏移 驱动里几乎不用(指针太多) "本体用点"
-> (箭头) 访问指向结构体的指针的成员 结构体指针 struct student *p; p->id = 100; 先解引用指针得到结构体地址,再加偏移 驱动里90% 用这个(filp->private_data 等) "指针用箭头"
结构体 把多个不同类型数据打包成一个"文件袋" 自定义类型 struct my_dev { int id; char name[32]; }; 连续内存块(可能有padding对齐) 必须用 container_of 从成员反推整个结构体 "文件袋"
container_of 从成员指针反推出整个结构体指针 内核链表/嵌入式结构体 dev = container_of(pos, struct my_dev, list); ptr - offsetof(结构体, 成员) 驱动灵魂!不掌握这个写不了任何现代驱动 "从零件找到整车"
相关推荐
剑神一笑18 小时前
Linux less 命令深度解析:从源码看分页器的设计智慧
linux·运维·less
IT大白鼠18 小时前
Dirty Frag漏洞深度分析:Linux内核页缓存污染漏洞的技术原理与安全防护
linux·安全·dirty frag漏洞
李白你好19 小时前
Linux 本地提权工具支持Linux 内核和 Polkit 漏洞
linux·运维·服务器
陳103019 小时前
Linux:System V IPC
linux·运维·服务器
aFakeProgramer19 小时前
在Ubuntu系统格式化SD卡,单分区/双分区
linux·运维·ubuntu
键盘上的GG小怪兽GG19 小时前
Debian 安装CUPS操作
linux·服务器·debian
Irene199119 小时前
Windows 11 WSL Ubuntu 环境:实际安装 Hadoop 踩坑实录
linux·hadoop·ubuntu
手可摘星辰的少年19 小时前
Ext2数据块寻址原理:直接块、间接块到三级间接块
linux
高翔·权衡之境19 小时前
主题9:DMA与零拷贝——让CPU从数据搬运中解放
驱动开发·安全·缓存·系统安全·信息与通信
Irene199119 小时前
nano 和 vim(Linux 默认安装)的区别(文本编辑器 vs 专业编辑器)
linux·vim·nano