嵌入式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高级编程》部分章节改编,视频学习可访问优快云学院:https://edu.youkuaiyun.com/combo/detail/1038

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

QQ群:475504428

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

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

我的博客:www.zhaixue.cc

宋宝华嵌入式 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
### 关于嵌入式C语言的学习资源 对于学习嵌入式C语言并深入了解其与芯片、编译器以及操作系统的关系,可以参考一些经典的书籍和资料。以下是针对这一领域的一些推荐: #### 推荐书籍 1. **《嵌入式C语言自我修养》** 这本书专注于嵌入式开发的基础知识,涵盖了从底层硬件到上层软件的设计理念[^3]。书中通过实际案例分析了如何利用C语言编写高效且稳定的嵌入式程序。 2. **《Linux内核揭密》易建勋** 此书不仅讲解了Linux内核的工作机制,还涉及到了部分嵌入式环境下的应用实例[^1]。它可以帮助读者了解操作系统层面的知识,这对于掌握嵌入式编程至关重要。 3. **《微型计算机原理与接口技术》吴宁** 该教材详细介绍了微处理器及其外围设备的工作方式,适合初学者构建对硬件平台的理解框架。 4. **《深入理解计算机系统》Randal E.Bryant 和 David R.O'Hallaron** 尽管这不是一本专门讨论嵌入式的书籍,但它提供了关于编译过程、内存管理等方面深刻见解[^4],这些概念同样适用于嵌入式环境中。 5. **《ARM体系结构程序员指南》Dominic Sweetman** 如果目标平台基于ARM架构,则此书非常有价值。它全面覆盖了ARM指令集及相关工具链使用方法[^5]。 #### 获取PDF版本的方法 为了合法获得上述提到的电子版文档,建议访问正规渠道如图书馆数据库或者购买正版授权副本。也可以尝试以下途径: - 学术机构提供的开放获取服务; - 出版商官网可能提供试读章节甚至整本下载链接(需注册账户); - 在线书店有时会附赠配套数字材料给纸质书买家; 请注意尊重版权法律,在未经授权情况下传播受保护作品属于违法行为。 ```bash # 示例命令用于查找本地是否有相关pdf文件 find ~/Documents -name "*嵌入式*C*自我修养*.pdf" ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宅学部落-王利涛

just for test

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值