用 union 包裹一个 struct 结构体

  union {
        /* Remap range. */
        struct {
            unsigned long start;
            unsigned long start_pfn;
            unsigned long size;
            pgprot_t pgprot;
        } remap;
    };

Linux 内核中一个非常典型的用法:用 union 包裹一个匿名结构体,用于表示不同的映射类型共享同一片内存区域。

1. 为扩展预留空间(最常见原因)
虽然现在 union 里只有一个 struct,但这是为了方便未来添加其他映射类型:

union {
    struct {
        unsigned long start;
        unsigned long start_pfn;
        unsigned long size;
        pgprot_t pgprot;
    } remap;        // 内存重映射类型
    
    struct {
        unsigned long pfn;
        unsigned long size;
        pgprot_t pgprot;
        int flags;
    } direct;       // 直接映射类型(未来扩展)
    
    struct {
        unsigned long vaddr;
        unsigned long size;
        int cache_flags;
    } iomap;        // IO 映射类型(未来扩展)
};

这样,不同的映射方式可以共用同一块内存,节省空间。

2. 确保结构体满足对齐要求
union 的对齐要求是其最大成员的对齐要求。虽然现在只有一个成员,但这种写法:
* 为将来扩展做好了准备
* 保证 start 等字段按 unsigned long 对齐(通常是 8 字节)
* 如果后续添加一个需要更大对齐的类型(如 long long 或 __int128),union 会自动适配

3. 代码组织与语义清晰
在内核代码中,这种写法通常出现在描述虚拟内存区域(VMA) 或 页表项 的结构体中:

struct vm_area_struct {
    // ... 其他字段
    union {
        struct {
            unsigned long start;
            unsigned long start_pfn;
            unsigned long size;
            pgprot_t pgprot;
        } remap;
        // 其他映射类型...
    };
    // ... 更多字段
};

* remap 这个名字清晰地表明:这块内存用于 remap(重新映射) 操作
* 当内核需要处理 remap_pfn_range() 这类函数时,使用 remap 字段
* 代码可读性大大提升

4. 避免命名空间污染
因为是匿名 union(C11 特性),使用时可以直接访问:

// 假设 vma 是这个结构体的指针
vma->remap.start = addr;      // 清晰
vma->remap.size = len;         // 直观

而不是:

vma->map_info.remap.start     // 多了一层
vma->map_info.direct.pfn      // 需要区分


内核例子
在 Linux 内核的 linux/mm.h 或 linux/io.h 相关代码中,这种模式真实存在:

// 简化的真实内核代码片段
struct remap_pfn_data {
    struct vm_area_struct *vma;
    unsigned long addr;
    unsigned long pfn;
    unsigned long size;
    pgprot_t prot;
};

// 在某个结构体中...
union map_info {
    struct {
        unsigned long start;
        unsigned long start_pfn;
        unsigned long size;
        pgprot_t pgprot;
    } remap;
    
    struct {
        unsigned long pfn;
        unsigned long size;
        unsigned long offset;
    } linear;
};


即使只有一个成员,这种写法也有价值:

* 面向未来的扩展:代码可能很快就会增加新的映射类型
* 统一的访问模式:所有映射类型都通过 remap、direct 等字段名访问
* 满足对齐要求:确保后面的字段(如果有)不会破坏 union 成员的对齐


这段代码总结:

* 当前功能:包含一个 remap 结构体,存储内存重映射需要的参数
* 设计意图:为未来添加其他映射类型(直接映射、IO 映射等)预留空间
* 技术价值:
    # 内存复用(不同映射类型不共存)
    # 对齐一致性(按最大成员对齐)
    # 代码可扩展性(添加新类型不影响现有代码)
    # 语义清晰(remap 名称明确表达用途)

这是 Linux 内核中非常优雅的 C 语言设计模式,体现了面向接口编程和预留扩展性的思想。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值