嵌入式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
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
嵌入式C语言自我修养:从芯片、编译器到操作系统这本书是一本关于嵌入式系统开发的教程。它以C语言作为主要的编程语言,通过探索嵌入式系统的各个层面,帮助读者深入理解嵌入式系统的工作原理和开发过程。 首先,这本书深入讲解了嵌入式系统的硬件层面,如芯片的基本概念、架构和工作原理。读者可以了解到不同芯片的特点和应用场景,以及如何选择适合自己需求的芯片。 其次,这本书详细介绍了编译器的原理和使用方法。编译器是将高级语言转化为机器码的重要工具,对于嵌入式系统的开发尤为关键。通过学习编译器的原理和使用方法,读者可以更好地编写高效、可靠的嵌入式程序。 最后,这本书还讨论了嵌入式操作系统的概念和应用。操作系统是管理硬件和软件资源的重要组成部分,对于嵌入式系统的开发非常重要。通过学习嵌入式操作系统的原理和使用方法,读者可以更好地理解和设计嵌入式系统,提高系统的性能和稳定性。 总之,嵌入式C语言自我修养:从芯片、编译器到操作系统这本书是一本全面介绍嵌入式系统开发的教材。它以C语言为基础,从硬件到软件各个层面深入讲解了嵌入式系统的原理和开发过程。对于想要深入了解嵌入式系统并提升开发能力的读者来说,这本书是一本不可多得的学习资料。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

宅学部落-王利涛

just for test

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

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

打赏作者

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

抵扣说明:

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

余额充值