嵌入式C语言自我修养 (13):总结

13.1 总结

前面12节的课程,主要针对 Linux 内核中 GNU C 扩展的一些常用 C 语言语法进行了分析。GNU C 的这些扩展语法,主要用来完善 C 语言标准和编译优化。而通过 C 标准的发展过程我们又发现,对于一些编译器扩展的一些特性,或者其它编程语言(如:C++)中的好的特性和语法,C 标准也会适时地吸收进来,作为新的 C 语言标准。

在 GNU C 的这些扩展语法中,__attribute__ 和宏定义是两大特色。在嵌入式底层系统中,尤其是 Linux 内核和 U-boot 中,大量使用 GNU C 扩展的 __attribute__属性去辅助一些底层机制的实现,或者实现一些编译上的优化。在宏定义方面,通过语句表达式、可变参数宏等特性,我们可以定义一个功能复杂、安全可靠的高质量宏。

本教程所讲的一些特性,都是在实际工作或阅读 Linux 内核驱动源码时经常遇见的一些特性,掌握了这些扩展特性的使用,以后再遇到类似的“奇葩 C 语言”程序,就知道怎么去分析了。除此之外,GNU C 还有一些其它扩展特性,由于他们在内核中用得不是很多,或者说仅仅是做一些编译上的优化,即使不知道也不会影响我们理解代码,限于篇幅关系,所以就暂时不讲了,比如下面这些特性。

  • 属性声明:const
  • 属性声明:constructor、destructor
  • 属性声明:noreturn
  • 属性声明:used、unused
  • 局部标签
  • 嵌套函数
  • ……

大家以后遇到类似的扩展,可以到下面这几个网站上去看看。

 

13.2 C 语言习题测试

下面是几道 C 语言练习题,大家可以做一做。看看学完本教程后,有没有真正的掌握。有什么疑问,可以通过读者圈,或加入QQ群(475504428)与我讨论。

1.下面的程序,在不同编译环境下,比如分别在 C-Free、VC++6.0、TurboC 环境下编译运行,结果是否相等,为什么?

#include<stdio.h>
int main(void)
{
    printf("size: %d\n", sizeof(int);
    return 0;
}

2.定义一个宏,求两个数的最小值。

3.将下面的程序编译为可以在 ARM 平台上运行的可执行文件 a.out,并对其进行反汇编,查看变量 global_val 的地址。

int global_val = 10;
int uninit_val;
int main(void)
{
    int local_val = 20;
    return 0;
}

4. 在一个工程项目中,有两个源文件如下,分析下面程序的运行结果。

//func.c
int a = 10;
int b;
int c __attribute__((weak)) = 30;
​
//main.c
int a;
int b = 20;
int c = 40;
int main(void)
{
    printf("a: %d\n",a);
    printf("b: %d\n",b);
    printf("c: %d\n",c);
    return 0;
}

5.定义一个变参函数,实现等级打印控制:ERROR、DEBUG、INFO。用这三个宏分别代表等级打印,比如定义 ERROR 时,只打印错误的信息;定义 DEBUG 时,打印错误和调试信息;定义 INFO 时,所有的打印信息都打印出来。

6.定义一个变参宏,实现等级打印控制:ERROR、DEBUG、INFO。用这三个宏分别代表等级打印,比如定义 ERROR 宏时,只打印错误的信息;定义 DEBUG 时,打印错误和调试信息;定义 INFO 时,所有的打印信息都打印出来。

7.下面是 Linux 内核(Linux4.4.0)中的一些宏定义,请分析它们实现的功能。

#define pr_emerg(fmt, ...) \
    printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
#define pr_alert(fmt, ...) \
    printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_crit(fmt, ...) \
    printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_err(fmt, ...) \
    printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warning(fmt, ...) \
    printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warn pr_warning
#define pr_notice(fmt, ...) \
    printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
#define pr_info(fmt, ...) \
    printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)

8.在 Linux 内核启动过程中,启动 log 的最后往往会有这么一行信息。

Freeing unused kernel memory: 468K

请用本课程中的 section 属性声明,分析这段 log 背后的内核初始化及内存释放过程。

9.在嵌入式 Linux 驱动开发中,驱动模块是没有 main() 入口函数的,请用本课程学过的知识分析:驱动是如何运行和初始化的。

10.驱动分析:在 linux4.4 源码 linux-4.4/arch/arm/mach-footbridge/ebsa285.c 中,分析下面代码的含义及 container_of 宏的作用。

MACHINE_START(EBSA285, "EBSA285")
    /* Maintainer: Russell King */
    .atag_offset    = 0x100,
    .video_start    = 0x000a0000,
    .video_end  = 0x000bffff,
    .map_io     = footbridge_map_io,
    .init_early = footbridge_sched_clock,
    .init_irq   = footbridge_init_irq,
    .init_time  = footbridge_timer_init,
    .restart    = footbridge_restart,
MACHINE_END
static void ebsa285_led_set(struct \
led_classdev *cdev, enum led_brightness b)
{
    struct ebsa285_led *led = container_of(cdev,
            struct ebsa285_led, cdev);
​
    if (b == LED_OFF)
        hw_led_state |= led->mask;
    else
        hw_led_state &= ~led->mask;
    writeb(hw_led_state, xbus);
}
​
static enum led_brightness \
ebsa285_led_get(struct led_classdev *cdev)
{
    struct ebsa285_led *led = container_of(cdev,
            struct ebsa285_led, cdev);
​
    return hw_led_state & led->mask ? LED_OFF : LED_FULL;
}

 

13.3 结束语

通过本课程的学习,再加上本节10个习题的练习,相信大家的 C 语言功底肯定又加深了一层!有了这些知识储备基础,基本上就扫除了 Linux 内核的阅读障碍。相信大家在以后的工作、学习中一定会日益精进,不断突破!

 

本文根据《C语言嵌入式Linux高级编程》部分章节改编,视频学习可访问CSDN学院:https://edu.csdn.net/combo/detail/1038

微信公众号:宅学部落(armlinuxfun)

QQ群:475504428

更多嵌入式视频教程:https://wanglitao.taobao.com

电子书籍下载地址:https://pan.baidu.com/s/1a6L0cyIQKKLlmIfRw7U6Dg

我的博客:www.zhaixue.cc

  • 0
    点赞
  • 7
    收藏
  • 打赏
    打赏
  • 0
    评论
<p><span style="color: #313d54; font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; font-size: 20px; background-color: #ffffff;">Linux内核一直是学习的难点:将近3000万行代码,5万多个源文件,代码庞大繁杂、代码很难看懂。《Linux内核编程》将突破以往传统的学习方式,采取更有效和科学的学习方法,多角度地对内核进行多层次分析,不局限于形式,不拘泥细节,目的只有一个:更轻松、更高效地去理解内核、学习内核。</span></p> <p><span style="color: #313d54; font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; font-size: 20px; background-color: #ffffff;"><img src="https://img-bss.csdnimg.cn/202012080248396715.png" alt="" /></span></p> <p style="font-family: tahoma, arial, 宋体, sans-serif; margin: 1.12em 0px; padding: 0px; color: #313d54; font-size: 14px; background-color: #ffffff;"><span style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; font-size: 20px;">为了更好地让学员掌握内核编程技能,更好地理解内核,本课程将采用并不局限于以下学习方法进行课程的录制:</span></p> <ul class=" list-paddingleft-2" style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; list-style: none; color: #313d54; font-size: 16px; background-color: #ffffff;"> <li style="margin: 0px; padding: 0px;"> <p style="margin: 0px; padding: 0px;"><span style="margin: 0px; padding: 0px; font-size: 20px;">降维分析,化简为繁,将复杂的系统简单化</span></p> </li> <li style="margin: 0px; padding: 0px;"> <p style="margin: 0px; padding: 0px;"><span style="margin: 0px; padding: 0px; font-size: 20px;">用软件工程的方法分析内核:软件分层、模块化分解、框架迭代</span></p> </li> <li style="margin: 0px; padding: 0px;"> <p style="margin: 0px; padding: 0px;"><span style="margin: 0px; padding: 0px; font-size: 20px;">多角度立体分析Linux内核,目的只有一个:更好地理解内核</span></p> </li> <li style="margin: 0px; padding: 0px;"> <p style="margin: 0px; padding: 0px;"><span style="margin: 0px; padding: 0px; font-size: 20px;">利用Linux内核中的面向对象编程思想去分析复杂的子系统、子系统交互</span></p> </li> <li style="margin: 0px; padding: 0px;"> <p style="margin: 0px; padding: 0px;"><span style="margin: 0px; padding: 0px; font-size: 20px;">利用多任务编程的思想去分析Linux内核</span></p> </li> </ul> <p><span style="margin: 0px; padding: 0px; font-size: 20px;"><img src="https://img-bss.csdnimg.cn/202012080249061133.png" alt="" /></span></p> <p style="font-family: tahoma, arial, 宋体, sans-serif; margin: 1.12em 0px; padding: 0px; color: #313d54; font-size: 14px; background-color: #ffffff;"><span style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; font-size: 20px;">本套课程预计分为20个左右的小模块,每个模块一个专题,每个专题会陆续发布。</span><span style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; font-size: 20px;">拟录制的模块包括但不限于:模块机制、内核裁剪与配置、内核编译与启动、系统调用、中断、文件系统、调度、内存管理、内核同步、设备模型、字符驱动、块驱动、定时器、input、platform设备驱动、device tree、proc、sysfs、I/O...</span></p> <p style="font-family: tahoma, arial, 宋体, sans-serif; margin: 1.12em 0px; padding: 0px; color: #313d54; font-size: 14px; background-color: #ffffff;"><span style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; font-size: 20px;"> </span></p> <p> </p> <p style="font-family: tahoma, arial, 宋体, sans-serif; margin: 1.12em 0px; padding: 0px; color: #313d54; font-size: 14px; background-color: #ffffff;"><span style="font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', Arial, sans-serif; margin: 0px; padding: 0px; font-size: 20px;">本课程是《Linux内核编程》的入门篇,主要给大家介绍一下Linux内核开发、Linux驱动开发的就业行情、行业生态、需要掌握哪些技能、Linux内核的学习方法、如何搭建Linux内核的学习开发环境。</span></p> <p> </p>
宋宝华嵌入式 C/C++语言精华文章集锦 C/C+语言 struct 深层探索 ............................................................................2 C++中 extern "C"含义深层探索........................................................................7 C 语言高效编程的几招...............................................................................11 想成为嵌入式程序员应知道的 0x10 个基本问题 .........................................................15 C 语言嵌入式系统编程修炼...........................................................................22 C 语言嵌入式系统编程修炼之一:背景篇 ............................................................22 C 语言嵌入式系统编程修炼之二:软件架构篇 ........................................................24 C 语言嵌入式系统编程修炼之三:内存操作 ..........................................................30 C 语言嵌入式系统编程修炼之四:屏幕操作 ..........................................................36 C 语言嵌入式系统编程修炼之五:键盘操作 ..........................................................43 C 语言嵌入式系统编程修炼之六:性能优化 ..........................................................46 C/C++语言 void 及 void 指针深层探索 .................................................................50 C/C++语言可变参数表深层探索 .......................................................................54 C/C++数组名与指针区别深层探索 .....................................................................60 C/C++程序员应聘常见面试题深入剖析(1) ..............................................................62 C/C++程序员应聘常见面试题深入剖析(2) ..............................................................67 一道著名外企面试题的抽丝剥茧 ......................................................................74 C/C++结构体的一个高级特性――指定成员的位数 .......................................................78 C/C++中的近指令、远指针和巨指针 ...................................................................80 从两道经典试题谈 C/C++中联合体(union)的使用 ......................................................81 基于 ARM 的嵌入式 Linux 移植真实体验 ................................................................83 基于 ARM 的嵌入式 Linux 移植真实体验(1)――基本概念 ...........................................83 基于 ARM 的嵌入式 Linux 移植真实体验(2)――BootLoader .........................................96 基于 ARM 的嵌入式 Linux 移植真实体验(3)――操作系统 ..........................................111 基于 ARM 的嵌入式 Linux 移植真实体验(4)――设备驱动 ..........................................120 基于 ARM 的嵌入式 Linux 移植真实体验(5)――应用实例 ..........................................135 深入浅出 Linux 设备驱动编程 .......................................................................144 1.Linux 内核模块..............................................................................144 2.字符设备驱动程序 ...........................................................................146 3.设备驱动中的并发控制 .......................................................................151 4.设备的阻塞与非阻塞操作 .....................................................................157

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

宅学部落-王利涛

just for test

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值