首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

Linux编程中C函数定义的第一行中出现的关键字“__init”是什么意思?

  • 25-03-05 05:21
  • 3287
  • 11634
blog.csdn.net

问题提出

在驱动程序模块的编写中,常常会在初始化函数的第一行中加上关键字“__init”,请问“__init”是什么意思?
比如下面的代码:

static int __init led_init(void) {
    // 初始化代码:注册设备、分配资源等
    return 0;
}

module_init(led_init);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

详细解释

__init 的作用

在 Linux 内核代码中,__init 是一个宏,用于标记初始化函数的代码段。这是一种内核的优化方式,旨在减少内核的内存占用。


__init 的功能

  1. 标记初始化代码:

    • 内核会将带有 __init 标记的代码放入一个特殊的内存区(.init.text 段)。
    • 这段内存在初始化完成后(通常是模块加载完成或内核启动完成后)会被释放,节省内存。
  2. 仅在初始化时执行:

    • 这些代码通常只需要在模块加载或系统启动时运行一次。
    • 运行结束后,它们不会再被调用。

使用 __init 的场景

  1. 模块初始化函数:

    • 像例子中的 led_init,是模块加载时的入口函数,只需要运行一次,因此使用 __init 标记。
    • 例如:
      static int __init led_init(void) {
          // 初始化代码
          return 0;
      }
      module_init(led_init);
      
      • 1
      • 2
      • 3
      • 4
      • 5
  2. 内核启动时的初始化代码:

    • 一些驱动程序或内核功能在启动时需要初始化,完成后可以释放相关的代码段。

内核如何处理 __init

  1. 编译时:

    • 编译器将标记为 __init 的代码放入 .init.text 段,而不是普通的代码段。
  2. 运行时:

    • 内核在启动或模块初始化时执行这些代码。
    • 一旦初始化完成,内核会释放 .init.text 段所占用的内存。

为什么要使用 __init?

  1. 节省内存:

    • Linux 内核运行在多种硬件上,包括资源受限的嵌入式设备。
    • 释放不再使用的初始化代码可以显著节省内存。
  2. 优化内核空间:

    • Linux 内核运行在内核态,所有代码和数据都必须驻留在内存中。
    • __init 可以减少不必要的代码驻留。

不使用 __init 的后果

  • 如果初始化函数没有用 __init 标记,即使在完成初始化后,相关代码仍然会占用内存,直到模块被卸载或系统重启。
  • 在嵌入式系统中,内存资源宝贵,未释放的初始化代码可能会影响系统性能。

与 __init 相关的宏

  1. __initdata:

    • 用于标记初始化数据。
    • 初始化完成后,数据段会被释放。
    • 例如:
      static int __initdata my_init_data = 42;
      
      • 1
  2. __exit:

    • 标记模块的退出函数。
    • 只有在支持动态加载模块的情况下,这些代码才会被编译和保留;否则会被忽略。
    • 例如:
      static void __exit led_exit(void) {
          // 退出代码
      }
      module_exit(led_exit);
      
      • 1
      • 2
      • 3
      • 4
  3. __exitdata:

    • 标记仅用于模块卸载时的数据。

例子分析

以下代码片段是模块的初始化函数,用 __init 优化内存:

static int __init led_init(void) {
    // 初始化代码:注册设备、分配资源等
    return 0;
}
module_init(led_init);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 工作原理:
    1. 当模块加载时,led_init 函数被调用。
    2. 由于函数被标记为 __init,它会被放入 .init.text 段。
    3. 加载完成后,.init.text 段会被释放,led_init 所占的内存被回收。

小结

__init 是 Linux 内核中的一个优化工具,用于标记初始化代码段。它的主要目的是节省内存和提升内核性能。在开发驱动程序或内核模块时,如果某些代码仅在初始化阶段需要运行,建议加上 __init 标记。

问:这样做符合C语言的语法规范吗?

答:它其实并不符合C语言的标准语法,但符合 C 语言的扩展语法规则,通过 GCC 编译器的扩展功能实现。

__init 的本质

__init 是一个宏,定义在 Linux 内核的头文件中(通常是 )。它的作用是通过 GCC 的编译器属性(attributes)将函数标记为特定的段(section)。这是一种扩展功能,超出了标准 C 的范围,但完全符合 GCC 支持的 C 语言扩展。

在 中,__init 的定义类似于:

#define __init __section(.init.text)
  • 1
  • __section 是另一个宏,用来指定代码的存储段。
  • .init.text 是内核专门为初始化代码保留的段。

当编译器看到函数前有 __init 时,会将该函数放入 .init.text 段,而不是普通的代码段。


为什么符合 C 语言规范?

在标准 C 中,函数定义的语法是:

[存储类修饰符] 返回类型 函数名(参数列表) { 函数体 }
  • 1
  • __init 在展开后并不会改变函数定义的基本形式,只是通过编译器扩展为函数添加了属性。
  • 使用 GCC 时,这种属性是完全合法的,并且是内核代码中常见的写法。

例如:
展开后的代码实际是:

static int __attribute__((section(".init.text"))) led_init(void) {
    // 初始化代码
    return 0;
}
  • 1
  • 2
  • 3
  • 4

这是 GCC 支持的标准扩展语法,并没有违反 C 语言的规则。


在非 GCC 编译器中会发生什么?

如果在非 GCC 或不支持 __section 扩展的编译器上使用,可能会出现以下情况:

  1. 编译失败:
    编译器无法识别 __init,会报语法错误。

  2. 需要适配:
    在这种情况下,可以通过条件编译避免问题。例如:

    #ifdef __GNUC__
    #define __init __section(.init.text)
    #else
    #define __init
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5

__init 的实际用途

  1. 将函数放到 .init.text 段。
  2. 初始化完成后释放 .init.text 段的内存,节省资源。

小结

虽然 __init 不是标准 C 的一部分,但它通过 GCC 的扩展功能实现,符合 C 语言的扩展语法规则。因此,它在 Linux 内核开发中是合法且常用的。使用 __init 不会改变函数定义的规范性,只是为函数添加了段属性,便于内核在运行时进行内存管理优化。

昊虹嵌入式技术交流群
QQ群名片
注:本文转载自blog.csdn.net的昊虹AI笔记的文章"https://blog.csdn.net/wenhao_ir/article/details/144903805"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top