0
问答首页 最新问题 热门问题 等待回答标签广场
我要提问

嵌入式

嵌入式系统经验分享

因为自己这几年来一直从事嵌入式系统底层驱动开发,操作系统uc/OS,文件系统维护以及平台搭建工作,在这几年的工作中学习到不少系统方面的经验,现写下来一来是分享给大家,二来是作一个总结,三来是望得到各位大虾的批评指正。现打算从如下几个方面分类总结一下:

(一),预处理

(二),可移植性

(三),警惕潜在危险

(四),对齐与大小端模式

(五),效能问题

(六),重入问题

好像很难得将一个方面的内容一刀切的划分到一个主题中,例如:宏定义既是属于预处理内容,又跟效能有关系,还涉及到潜在危险... 所以,(一),(二),(三)...的划分不一定规范(咱又不是写书 ^_^),且会在不同的地方对某个问题进行不同重点的总结。

============ 预处理 ================

1.    头文件

一般来讲很难保证在一个大型的项目软件中,某个头文件不被重复的引用,例如,在嵌入式系统中往往为了软件的可移植性,都会有一个对所有数据类型的采用宏定义或者typedef定义的头文件,我们假定为portable.h,其内容如下:

#define INT8S  char

#define INT8U  unsigned char

#define INT16S  short

#define INT16U  unsigned short

#define INT32S  int

#define INT32U  unsigned int

类似于这种类型的头文件肯定会被其他的头文件多次引用,假定有component.h 和system.h两个头文件引用了portable.h,而在某个.c文件中引用了component.h和system.h那么编译器在进行预处理的时候会对这个.c文件中引用的所有头文件进行展开,这样portable.h中的宏定义会被多次展开,编译器发现有多次重复定义同一个宏定义的问题,那么编译器会报错/报警告。

为了避免这样的问题,我们对每个头文件加入条件编译。

#ifndef __portable_h__

#define __portable_h__

#define INT8S  char

#define INT8U  unsigned char

#define INT16S  short

#define INT16U  unsigned short

#define INT32S  int

#define INT32U  unsigned int

#endif

这样当,portable.h头文件在某个地方被展开后就会#define __portable_h__,那么在其他的地方有重复引用portable.h时,#ifndef __portable_h__ 是不成立的,所以,就不会对portable.h的内容重复展开了.

2.    条件预处理

#if ,#else, #endif应该是大家经常会用到的。

比如说,有两段代码在前期调试的时候会经常切换使用不同的代码,那么我们可能会写成如下方式:

形式1:

#if  0

gTestCount = a + b;

…….

#else

        gTestCount = (a<<1) + b;

        ……

#endif

这种方式是最简单也最直观的,下面还有几种条件预处理也非常有用,可能大家并不一定熟悉,至少我刚开始写代码的时候就不太熟悉 :)

形式2:

#ifdef __DEBUG_MODE__

        #define DEBUG_INFO        show_debug_info();

#else

        #define DEBUG_INFO        

#endif

形式3:

#ifndef __DEBUG_MODE__

        #define DEBUG_INFO        

#else

        #define DEBUG_INFO        show_debug_info();

#endif

形式4:

#ifndef __NOT_DEBUG_MODE__

        #define DEBUG_INFO        

#else

        #define DEBUG_INFO        show_debug_info();

#endif

也许,有人会觉得上面两种方式都是一样,其实,适时地巧妙地运用会给自己带来很多不必要的麻烦,特别是当这些定义是开放给用户去定义时,往往不可预知用户一定不会定义错误,比如可能用户会将#define __NOT_DEBUG_MODE__不小心

#define __NO_DEBUG_MODE__ 等等。

形式5:

#if __DEBUG_MODE__ = = 1

     ……

#else

……

#endif

形式6:

#if __DEBUG_MODE__ = = 1

  ……

#elif __DEBUG_MODE__ = = 2

  ……

#else

   DEBUG MODE DEFINE ERROR!!!!

#endi

形式7:

#if defined __DEBUG_MODE__

   ……

#elif defined __NOT_DEBUG_MODE__

   ……

#else

     DEBUG MODE DEFINE ERROR!!!!

#endif

3.    宏定义

有时候为了程序(性能/简洁…)的要求,我们往往会在写程序的时候写一些宏代码来满足,这是个好的习惯,但千万不要忘记了所有宏定义一定要加上括号,来保证宏定义在任何地方展开都不会有语法/逻辑错误,语法错误还好,编译器在编译的时候会给你指出来,但是逻辑错误,就……

注意:宏定义在预处理时只是对引用宏的地方做简单的字符替换!

对于表达式型的宏定义一定要加小括号();对于功能型的宏定义一定要加大括号。(不知道这里对于表达式和功能性的两个限定词是否准确 :))

例如:

表达式宏定义:

有如下语句使用宏定义EXPRESS_MACRO c* EXPRESS_MACRO,其本意是c*(a+b)

(1),不加括号

#define EXPRESS_MACRO  a+b

c* EXPRESS_MACRO, 展开后变成c*a+b

(2), 加括号

#define EXPRESS_MACRO  (a+b)

c* EXPRESS_MACRO, 展开后变成c*(a+b)

有如下语句使用宏定义FUNCTION_MACRO

if(…)

FUNCTION_MACRO

其本意是

if(…)

{

  c=a+b;

d=a*b;

}

(1),不加括号

#define TEST_MACRO   c= a+b; d= a*b;

if(…)

FUNCTION_MACRO

展开后变成:

if(…)

c=a+b;

d=a*b;

很严重的逻辑错误…

(2),加括号

#define TEST_MACRO   {c= a+b; d= a*b;}

if(…)

FUNCTION_MACRO

展开后变成:

if(…)

{

c=a+b;

d=a*b;

}

本来宏定义的这些问题打算归结到 (三),警惕潜在危险 中去总结的,但考虑到开篇总的多写一些内容,就在这里一并总结了吧 :)

3.#define 与typedef

#define 在编译预处理时进行处理,不会做任何类型检查

typedef 是属于编译的时候处理,编译的时候会做类型检查.br />

提问者:jinxibin 地点:- 浏览次数:5607 提问时间:10-26 16:32
我有更好的答案
提 交
撰写答案
提 交
1 / 3
1 / 3
相关嵌入式
一种嵌入式汽车数字仪表电路设计
作为一个新人,怎样学习嵌入式Linux
嵌入式多屏异显在卡拉OK点唱机中的运用
嵌入式操作系统 文件系统
优秀的嵌入式程序特点