17条嵌入式C语言编程小知识总结
- 流水线被指令填满时才能发挥最大效能,即每时钟周期完成一条指令的执行(仅指单周期指令)。
如果程序发生跳转,流水线会被清空,这将需要几个时钟才能使流水线再次填满。因此,尽量少的使用跳转指令可以提高程序执行效率,解决发案就是尽量使用指令的“条件执行”功能。
2. 在LPC2200系列中:
可以通过过下面的程序延迟10毫秒:
for(i=0;i<200;i++)
{
for(j=0;j<200;j++);
}
3. 通过下面语句将一个16位的变量放在两个8位的变量中。
//IP数据报总长度高字节
IpHeadUint8[10]=(IpHead.e_ip.Crc&0xff00)>>8;
//IP数据报总长度低字节
IpHeadUint8[11]=IpHead.e_ip.Crc&0x00ff;
4. 在对全部数组元素赋初值时,可以不指定数组长度。
eg;inta={1,2,3,4,5};
但如果当输出第a[5]以上的元素时,系统回输出随机数值,所以使用此方法时,不能使用超过初始值元素以上的元素。
5. 由于ADS先天性的对printf不支持;因此不便于我们调试,可以利用串口输出来代替printf来调试。
6. 用或运算,可使某位置为1,其它位不变
eg: PINSEL0 |= 0x00000005; //设置串口引脚
使第0位和第二位置一,其他位不变。
7. 函数指针
1> C语言中函数名直接对应于函数生成的指令代码在内存中的地址,因此函数名可以直接赋给指向函数的指针。
2> 调用函数实际上等同于“调用指令+参数传递处理+回归位置入栈”,本质上最核心的操作是将函数生成的目标代码的首地址赋给CPU的PC寄存器。
3> 因为函数调用的本质是跳转到某一个地址单元的code去执行,所以可以“调用一个根本就不存在在函数实体。
4> int (*p);定义p是一个指向函数的指针变量,次函数返回带回整型的返回值。*P两侧的括号不能省略,表示p先于*结合,是指针变量,然后再与后面的结合,表示此指针指向函
区别:int *p表示这个函数的返回值是指向整型变量的指针。
说明:
(1) 指向函数的指针变量的一般定义形式为:
数据类型 (*指针变量名);
1> 此处的“数据类型”是指函数返回值的类型
(2) 返回指针值的函数:
类型名 *函数名(参数表)
eg: int * func(int x,int y)
func是函数名,调用它以后能返回一个指向整型数据的指针。x,y是func的形参。区别方法:
a.从右往左找第一个括号,括号里面的是函数的形参。
b.括号外面的第一个标识符是函数的名字,函数前面的表示函数的返回数值。
8. 数组指针
1>int (*p)[4]
表示*p有4个元素,每个元素为整型。也就是p所指的对象有4个整型元素的数组,既P是行指针。
2> 指针数组
Ø 一个数组,其元素均为指针类型数据,称为指针数组;即指针数组中的每一个元素都相当于一个指针变量。
Ø 一维指针数组的定义形式为:
类型名 *数组名[数组长度]
eg:int *p[4]:
作用:它用于指向若干个字符串,使字符串处理更加方便灵活。适用于一个二维字符串数组,其中每一行的字符数组的长度各不相同
eg:char * name={“Follow me”,”BASIC”,”GreatWall”};
9. 结构体
1> 可以用结构体变量做实参。但是用结构体变量作实参时,采取的是“值传递”的方式,将结构体变量所占的内存单元的内容全部顺序递给形参。形参也必须是同类型的结构体变量。
eg:pint(su);//注在此处su为结构体
注:这种传递方式在空间和时间上开销较大,如果结构体的规模较大时,开销是很可观的。
2> 用直向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址传给形参
eg:print(&su);//注在此处su为结构体
10. 共用体
1> 共用体把几种不同数据类型的变量存放在同一块内存里。公用体中的变量共享同一块内存。
2> 定义公用体类型变量的一般形式为:
union 共用体名
{
成员列表;
}变量列表;
3>在共用体中同一块内存可以用来存放几种不同类型的数据,但在某一时刻只能在其中存放一个成员变量。共用体变量中起作用的成员是最后一次存入的数据。
eg: union data
{
int i;
char c;
double d;
};
union data a;
共用体变量a中的成员i,c,d三个变量在内存中从同一个地址开始存储。如进行如下赋值:
a.i = 100;
a.c = ‘A’;
那么此时共用体变量a中的成员i已经没有值了,因为存储该值的内存现在已经被用来存储成员c的值了。
3> 共用体变量的长度取决于其成员的最大长度:
说明:
结构体变量所占内存的长度是各个成员的总和,每个成员分别占有自己的存储空间。共用体变量所占内存的长度是其最长成员的长度。当然,编译器出于提高访问效率的目的,在编译分配存储空间时往往要进行对齐操作。
对齐操作以最大基本类型为准。即以最大基本类型为基本单元。若按实际算下的长度不是基本单元的整数倍,则其实际长度应该是基本单元的整数倍。
(在TurboC中不进行对齐,在Linux中进行对齐)
11. CPU字长与存储器位宽不一致处理
例如:使用共用体来解决这一冲突:
union send_temp{
uint16 words;
uint8 bytes[2];
}send_buff;
eg:send_buff.bytes[0]=a;//此处a 是8位
send_buff.bytes[1]=b;//此处 b 是8位;
此时就将8位字拼成了16位字存储了。
发送时send(send_buff.words)就可以每次发送一个16位的数据了。
12. C语言符号优先级:
1>复合赋值运算符号:
a+=3*5;
等价于a=a+(3*5);
- 一个常见的调试策略是把一些printf函数的调用散布于程序中,确定错误出现的具体位置。
但是,这些函数调用的输出结果被写入到缓冲区中,并不立即显示于屏幕上。事实上,如果程序失败,缓冲输去可能不会被实际写入,因此得到的错误位置就是错误的。解决的方法是在每个用于调试的printf函数之后立即调用fflush函数即可得到。
printf(“something or other”);
fflush(stdout);
14.关键字volatile的用法
volatile变量可能用于如下几种情况:
1>设备的硬件寄存器(如:状态寄存器)
2>一个中断服务子程序中会访问到的全局变量
3>多线程应用中被几个任务共享的变量。
15.关键字register的用法:
当对一个变量频繁被读写时,需要反复访问内存,从而花费大量的存取时间。为此,C语言提供了一种变量,即寄存器变量。这种变量存放在CPU的寄存器中,使用时,不需要访问内存,而直接从寄存器中读写,从而提高效率。寄存器变量的说明符是register。对于循环次数较多的循环控制变量及循环体内反复使用的变量均可定义为寄存器变量,而循环计数是应用寄存器变量的最好候选者。
(1) 只有局部自动变量和形参才可以定义为寄存器变量。因为寄存器变量属于动态存储方式,凡需要采用静态存储方式的量都不能定义为寄存器变量,包括:模块间全局变量、模块内全局变量、局部static变量;
(2) register是一个"建议"型关键字,意指程序建议该变量放在寄存器中,但最终该变量可能因为条件不满足并未成为寄存器变量,而是被放在了存储器中,但编译器中并不报错(在C++语言中有另一个"建议"型关键字:inline)。
16.对于程序代码,已经被烧录在FLASH或ROM中,我们可以让CPU直接从其中读取代码执行,但通常这不是一个好办法,我们最好在系统启动后将FLASH或ROM中的目标代码拷贝入RAM中后再执行以提高取指令速度。
CPU对各种存储器的访问速度,基本上是:
CPU内部RAM > 外部同步RAM > 外部异步RAM > FLASH/ROM
17. 宏定义
在C语言中,宏是产生内嵌代码的唯一方法。对于嵌入式系统而言,为了能达到性能要求,宏是一种很好的代替函数的方法。
1>宏定义“像”函数;
2>宏定义不是函数,因而需要括上所有“参数”;
3>宏定义可能产生副作用。因而不要给宏定义传入有副作用的"参数"。
17条嵌入式C语言编程小知识总结的更多相关文章
- 嵌入式C语言优化小技巧
嵌入式C语言优化小技巧 1 概述 嵌入式系统是指完成一种或几种特定功能的计算机系统,具有自动化程度高,响应速度快等优点,目前已广泛应用于消费电子,工业控制等领域.嵌入式系统受其使用的硬件以及运行环境的 ...
- 嵌入式 C 语言编程总结
嵌入式 C 语言编程总结 目录: 全局变量 1.全局变量 在纯 C 语言(Pure C)开发的嵌入式程序中,需要在多处用到同一个变量,需要注意几点: 不要在头文件中对变量进行定义 头文件中变量的声明添 ...
- C++编程小知识随手记
C++编程小知识点: (1)queue和vector类型: 加入元素 : queue是queue.push(),vector是vector.push_back(), 删除元素: queue是queue ...
- iOS 编程小知识 之 本地化
1. 使用本地化多语言 有时候,在网上下载的Demo,有本地化的处理,默认的本地化都是英文,这时候,可以考虑这么处理: info.plist->Infomation Property List ...
- C语言struct小知识
1.C语言里的struct是不能包含成员函数的,只能有数据成员2.C语言struct定义变量只能用一下两种方式:struct { ... } x, y, z;struct point pt;直接poi ...
- go语言编程小tips
go语言一个比较方便的特性是你不需要显示的定义一个变量.例如,在c语言中,你想要使用一个int型变量,那么代码如下 int i; i =0; i++; 而在go语言中, i := 0; i++ 这样你 ...
- C语言编程小tip
1. 随机数产生 int rand(void)产生的随机数每次运行时都是与上一次相同,若要不同,用函数srand()初始化之. void srand(unsigned int seed)初始化随机数发 ...
- 【转】 嵌入式C语言编程中Inline函数的应用
源地址:https://blog.csdn.net/vigour1000/article/details/9622037 有一段儿时间没写写经验笔记了,哎,也是自己这一段时间以来(其实最近一直是这个状 ...
- c语言 相关小知识
软件运行与内存关系(垃圾数据) 内存是在操作系统的统一管理下使用的! 1.软件在运行前需要向操作系统申请访问存储空间,在内存空闲空间足够时,操作系统将分配一段内存空间并将外存中软件拷贝一份存入该内存空 ...
随机推荐
- 编译Spring5.2.0源码
下载 spring-framework-5.2.0.RELEASE.zip https://github.com/spring-projects/spring-framework/releases 下 ...
- Spring Security(五) —— 动手实现一个 IP_Login
摘要: 原创出处 https://www.cnkirito.moe/spring-security-5/ 「老徐」欢迎转载,保留摘要,谢谢! 5 动手实现一个IP_Login 在开始这篇文章之前,我们 ...
- 修改CentOS7登录欢迎界面信息
vi /etc/issue 添加自己喜欢的内容,保存即可. 特殊字符的含义: \d 本地端时间的日期: \l 显示第几个终端机接口: \m 显示硬件的等级 (i386/i486/i586/i686.. ...
- debian10 安装 详解
准备 下载debian 下载页面,有3个iso,选择第一个,其他两个软件包,我们不需要. 制作启动盘 debian官方提供了一个工具,可以轻松制作启动盘,也可以用opensuse官方提供的一个工具ru ...
- git bash中提示 bash:node: command not found
昨天小伙伴私信,git bash以及windows 的cmd命令行下均无法运行node npm. 究其原因是环境变量的问题.解决步骤: 1>在"此电脑"中右击,选择" ...
- linux新用户(组)的那些事
linux新用户(组)的那些事 创建新用户 groupadd bigdata //添加新用户组bigdata useradd -g bigdata es //-g:为用户组添加新用户 passwd ...
- XSS与CSRF定义
一. CSRF 1. CSRF的基本概念 跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通 ...
- VirtualBox安装centos8
原文链接:https://www.wjcms.net/archives/vagrantbox安装centos8 VirtualBox安装centos8 在线安装(不推荐) 打开git软件,直接运行命令 ...
- 安装visual stdio 2017后依然报错:Unable to find vcvarsall.bat
安装visual stdio 2017后依然报错:Unable to find vcvarsall.bat 解决办法:更新setuptools 原文章:https://blog.csdn.net/wl ...
- python 生成器(二):生成器基础(二)惰性实现
简介 设计 Iterator 接口时考虑到了惰性:next(my_iterator) 一次生成一个元素.懒惰的反义词是急迫,其实,惰性求值(lazy evaluation)和及早求值(eager ev ...