文章目录

  • |-引言 —— C语言中.h文件的作用
  • |-条件编译的作用
  • |-从C到hex/exe
    • 编译
    • 链接
  • |-extern关键字
    • 编译阶段
    • 链接阶段
  • |-static变量和全局变量
  • |- #pragma的作用
  • |-宏定义 #define
  • |- 定点数
  • 结个尾

本文转载并改编自董淑成 基于模型的设计 微信公众号,侵删,原文链接 https://mp.weixin.qq.com/s/c4G907PBnyHMI_uMrCmSlw

工作过程中,随着使用Simulink建模的深入,越发觉得C语言的重要性,尤其是将自动生成的代码与底层代码做集成的时,如果不了解C语言,在开发过程中很不方便。

|-引言 —— C语言中.h文件的作用

当前技术背景下,工程化的项目已经没有小到一个文件就可以搞定的了,但凡有点规模的项目,基本上都是模块化开发的。模块化开发的时候,对应每个模块,通常会写两个文件,一个.c,另一个.h,比如module1.c,module1.h
.c文件通常用于定义变量和实现函数,而.h文件,除了定义一些公用的宏和类型之外,还会有下面这样的代码:

      extern uint8 var1;extern uint8 var2;extern void myfunction(void);

这里 var1、var2是全局变量,而myfunction()是全局函数。

.h文件的主要作用是接口,不同模块之间的接口
举个例子:在module2模块中如果要用到module1里面定义的全局变量或者全局函数,只要在module2.h文件中加这样一样代码:#include “module1.h”。负责module1模块的工程师,如果想调用module2模块提供的全局函数,也只要看一下module2.h即可。

所以老胡经常跟用户强调不要去读自动生成的代码,如果一定要读,也只要读.h文件即可。

我们在.h文件中经常会看到这样一段代码:

#ifndef _MODULE1_H_
#define _MODULE1_H_

然后在.h文件的最末尾有:

#endif

这样的代码在.c文件中没有,请问,这又是什么意思?下面给出答案

|-条件编译的作用

举个例子:如果一个项目有10个模块,module1为其中的一个模块,其他模块在用到module1中定义的全局变量或者全局函数的时候,通常会在自己模块的.h文件中加这样一行代码#include “module1.h”

问题来了:如果10个模块中的9个模块都有这样一行代码,在预编译的时候,就会重复加载很多次module1.h文件。怎么解决这个问题?

可以通过宏_MODULE1_H_来确认是否已经加载过module1.h里的代码,第一次加载的时候,发现没有定义过宏_MODULE1_H_,也就是#ifndef _MODULE1_H_为真,于是定义这个宏,并加载后面的代码,在第二次再遇到#include “module1.h”的时候,已经有_MODULE1_H_这个宏了,#ifndef _MODULE1_H_后面的内容就不再被考虑,直接到#endif。

条件编译,顾名思义,也就是条件成立的时候给后面的内容做编译,条件不成立,则直接跳过。

|-从C到hex/exe

编译,通常我们会说把C编译成hex文件。其实,这种说法是不准确的,当然,你也可以认为这里的编译是广义上的编译,也就是我们经常在各种编译工具中的IDE界面下看到的Build,没错,Build更准确一些(Build是否应该翻译成“构建”?)。
从C到hex的整个Build过程会经历编译链接两个阶段。

编译

编译,就是把C代码转换成目标代码,通常扩展名为.obj或者.o。
目标代码不是最终的二进制码,目标代码中没有代码和变量的地址信息,编译过程中不会提示你某个变量没有定义或者某个变量被多次定义,只要你合理的使用extern关键字。

链接

地址信息是在链接(Link)过程中加上去的,链接器会把编译好的目标代码根据链接文件,把代码和数据分配到合适的存储区域。

|-extern关键字

编译阶段

这个关键字是给编译器看的,编译器遇到这个关键字,就知道这个关键字修饰的那个全局变量或者全局函数不在本文件中定义,而是在其他文件中有定义,所以编译器在编译本文件的时候不会因为没有定义这个全局变量或者全局函数而提示“未定义”之类的错误。

链接阶段

当然,如果到了链接阶段,链接器找遍了所有的目标文件,都找不到你所谓的extern变量的话,那个时候,链接器就会提示undefined reference 了。

|-static变量和全局变量

C语言中static变量和全局变量一样,编译、链接之后会分配固定的RAM地址,不同的是,static变量的作用域仅限于文件级别,你没法让module1中定义的staitc变量被module2模块使用,自然,加了static关键字的变量,也不会在module1.h文件中做extern声明。

另外,static除了可以修饰变量之外,还可以修饰函数。

换言之,static和extern两个关键字不能同时出现。

|- #pragma的作用

翻开C标准,你会发现,#pragma在标准里并没有明确的定义,而是预留给编译器扩展使用,通常,大多数编译器使用如下格式使用:

#pragma mysection begin
Uint8 var1;
Uint16 var2;
#pragma mysection end

需要强调的是这种格式并非标准化的格式,不同的编译器之间可能有所不同,使用前需要查看编译器手册,使用正确的格式

上面的4行代码是什么作用呢?中间两行显然是定义了两个变量var1和var2,前后的两行#pragma是把这两个变量放到了mysection区域,而这个mysection的地址范围是在link文件中定义的。
当然,也可以使用@将变量分配到某一地址下,不过这种做法在Simulink模型中实现起来非常麻烦,不建议使用。

|-宏定义 #define

关于#define,我们在代码中可能会看到这样一些使用方式

 #define MY_MACRO#define  K      30#define MAX(a,b)  (a>b)?a:b

先说第一种,就是定义了MY_MACRO,MY_MACRO就是一个宏,这个宏就像一个标记,后续代码可以判断是否有这个宏,有的话怎么样,没有的话又怎么样,.h的文件最开始的那段,就是这种用法。
第二种,就是把K定义为30,后续代码中凡是遇到K的地方,编译器编译的时候,就直接替换成30。
第三种,相当于用宏的方式定义了一个函数,跟普通的函数定义不同,在宏定义函数的时候无需定义形参的数据类型,而普通函数的形参是需要定义数据类型的,为什么呢?

在函数中,形参和实参是两个不同的变量,都有自己的作用域,调用时要把实参的值传递给形参;而在带参数的宏中,只是符号的替换,不存在值传递的问题,所以不需要定义形参数据类型

|- 定点数

定点数就是用整数来表达小数,计算机里并没有定点数这种东西,所以我们在定义数据类型的时候,Simulink模型中可能会使用fixdt,而到C代码中,只能看到uint16,uint32等等。定点数中的小数点,是我们假设的,我们会在整数的某个位置假设有一个小数点,那么小数点左边的是整数部分,小数点右边的是小数部分,当然这些计算机并不知道,它依然当成整数运算处理,所以对于编程者来说,需要在运算前后做一些移位对齐小数点的工作,如果你用Simulink模型开发软件,移位对齐工作就不需要你去折腾了,代码生成的时候会被考虑进去。

结个尾

原文作者老胡给MBD开发者的建议是 simulink、stateflow要学,S函数和TLC不要碰,之前不理解,现在很有道理。
举个例子: waijung早期推出基于STM32的MBD开发平台,就是利用一大堆TLC实现底层驱动。之前还觉得有用,现在发现只需要使用STM32CubeMX做底层配置,再加一点自己需要的底层代码,Simulink推出的C Caller完美解决上述问题。

[Simulink] MBD开发嵌入式软件的C语言基础相关推荐

  1. 黑马程序员_IOS开发简介和C语言基础

    (一)IOS开发简介: (1)IOS开发: IOS开发就是开发运行在IOS环境系统的软件.apple公司2009年推出开发包和环境,国内2010年iphone4问世,从而相 继出现开发者---> ...

  2. IOS开发入门之一——Swift语言基础

    需要iOS视频资料可以加我微信: 1914532832  验证信息请注明:IOS开发 很多新人对IOS开发很迷茫,不知道从何下手?看完本系列,你将会觉得IOS入门其实很简单.要学习IOS开发,当然是先 ...

  3. c语言中shift f12组合建,C++学习1-(C语言基础、VS快捷键)

    C语言基础复习 1.三码 正数: 3码合1 ,正数的反码/补码就是其本身 负数: 原码就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值 原码:11010101 负数的反码是在其原码的基础上 ...

  4. c语言教程在线阅读,《C语言基础教程》.doc

    <C语言基础教程>.doc C语言基础教程(一) 网上收集整理 Turbo C语言概述 1.1 C 语言的产生与发展 C 语言是1972年由美国的Dennis Ritchie设计发明的, ...

  5. day01计算机基础知识Java语言基础

    计算机基础知识(计算机概述) 计算机基础知识(软件开发和计算机语言概述) 计算机基础知识(人机交互) 计算机基础知识(键盘功能键和快捷键) 计算机基础知识(如何打开DOS控制台) 计算机基础知识(常见 ...

  6. 小智学长嵌入式入门学习路线_1 C语言基础

    原课程链接: 嵌入式开发系统学习路线 从基础到项目 精品教程 单片机工程师必备课程 物联网开发 c语言 2022追更 前言 在学习过程中,老师提到了一个很重要的思想:主要从学习嵌入式的角度学习各项技能 ...

  7. C语言基础:MBD与C语言

    本文简单介绍一下博主对MBD与C语言的认识. 文章目录 1 MBD中的C语言 1.1 MBD中使用C语言的原因 1.2 MBD中使用C语言的场景 1.3 学习MBD中的C语言 2 手写C代码 2.1 ...

  8. 系列:iOS开发-C语言基础

    #系列:iOS开发-C语言基础 之前也说了iOS中的OC是扩充C的面向对象编程语言 那么无论是从什么角度来说都要首先回顾一下C的内容,虽然很多人在大学的时候都有学习过C语言,一提到谭浩强,我估计90% ...

  9. ios c语言头文件,iOS开发 -- C语言基础12(预处理指令)

    iOS开发 -- C语言基础12(预处理指令) 宏定义 预处理指令简介 1.C语言在对源程序进行编译之前,会先对一些特殊的预处理指令作解释(比如之前使用的#include文件包含指令),产生一个新的源 ...

最新文章

  1. EV代码签名证书,支持Windows 10预览版和正式版驱动签名
  2. CSS transition delay简介与进阶应用
  3. python 网站文件下载-python实现下载文件的三种方法
  4. 图解在emu8086中学习汇编语言数字比较程序
  5. SD-SD用到的文本对象列表
  6. 01Spring的helloworld程序
  7. Angular源代码里字母Theta的含义
  8. [零基础,全开源]基于web的远程深度学习服务搭建
  9. .bat是什么语言_简单说说当我们打开网页时,浏览器到底做了什么?
  10. 微众银行软件测试笔试题,微众银行4月8日笔试题目及部分代码
  11. 在子线程中更改主线程中的控件的信息,在子线程中用toast
  12. 三层构架和 MVC 不同?
  13. Java Web(十) JDBC的增删改查,C3P0等连接池,dbutils框架的使用
  14. 如何用计算机还原魔方,初学者使用的魔方口诀 7步教你快速复原三阶魔方(附图解)...
  15. Android超声波识别技术,超声波指纹识别or光学指纹识别?屏下指纹识别技术大比拼-传感技术-与非网...
  16. R语言案例分析:多元数据的基本统计分析
  17. 为什么那么多程序员害怕Python?
  18. 产业互联网,一次从需求侧向供给侧的自我嬗变
  19. 西北工业大学计算机学院教授张凯龙,张凯龙
  20. ARP局域网断网攻击原理分析及演示

热门文章

  1. 楚留香服务器维护,楚留香手游7月20日更新维护内容及家园系统详解介绍
  2. 关于python的英文参考文献_中英文参考文献
  3. 你知道Java是世界第一的秘密吗?
  4. v-if控制元素的显示与隐藏
  5. HR hrp9505创建更新部门信息RH_PNNNN_MAINTAIN,PPOME查看部门信息时可看到对勾
  6. am82.top 1.php,PHP下的异步尝试一:初识生成器
  7. MIT-JOS系列4:内存管理
  8. 用TransMac制作macos X系统启动安装U盘不能引导的原因
  9. 云计算中的存储虚拟化技术应用
  10. python 3d绘图 拖动_使用Matplotlib轻松搞定3D绘图