博文

C语言高效编程的的四招技巧(2008-05-06 20:23:00)

摘要:引言:   编写高效简洁的c语言代码,是许多软件工程师追求的目标。本文就工作中的一些体会和经验做相关的阐述,不对的地方请各位指教。   第一招:以空间换时间   计算机程序中最大的矛盾是空间和时间的矛盾,那么,从这个角度出发逆向思维来考虑程序的效率问题,我们就有了解决问题的第1招--以空间换时间。   例如:字符串的赋值。   方法a:通常的办法: #define len 32
char string1 [len];
memset (string1,0,len);
strcpy (string1,"this is a example!!");
  方法b: const char string2[len] ="this is a example!";
char * cp;
cp = string2 ;
  使用的时候可以直接用指针来操作。   从上面的例子可以看出,a和b的效率是不能比的。在同样的存储空间下,b直接使用指针就可以操作了,而a需要调用两个字符函数才能完成。b的缺点在于灵活性没有a好。在需要频繁更改一个字符串内容的时候,a具有更好的灵活性;如果采用方法b,则需要预存许多字符串,虽然占用了大量的内存,但是获得了程序执行的高效率。
如果系统的实时性要求很高,内存还有一些,那我推荐你使用该招数。该招数的变招--使用宏函数而不是函数。举例如下:   方法c: #define bwmcdr2_address 4
#define bsmcdr2_address 17
int bit_mask(int __bf)
{
 return ((1u << (bw ## __bf)) - 1) << (bs ## __bf);
}
void set_bits(int __dst, int __bf, int __val)
{
 __dst = ((__dst) & ~(bit_mask(__bf))) |
 (((__val) << (bs ## __bf)) & (bit_mask(__bf))))
} set_bits(mcdr2, mcdr2_address, register......

阅读全文(1380) | 评论:0

C++中const总结(2008-04-17 21:44:00)

摘要:一:对于基本声明
1.const int r=100;
//标准const变量声明加初始化,因为默认内部连接所以必须被初始化,其作用域
为此文件,编译器经过类型检查后直接用100在编译时替换.

2.extend const int r=100;
//将const改为外部连接,作用于扩大至全局,编译时会分配内存,并且可以不进行
初始化,仅仅作为声明,编译器认为在程序其他地方进行了定义.

3.const int r[]={1,2,3,4};
struct S {int a,b;};
const S s[]={(1,2),(3.4)};
//以上两种都是常量集合,编译器会为其分配内存,所以不能在编译期间使用其中
的值,例如:int temp[r[2]];这样的编译器会报告不能找到常量表达式

二:对于指针
1.const int *r=&x;
//声明r为一个指向常量的x的指针,r指向的对象不能被修改,但他可以指向任何
地址的常量.

2.int const *r=&x;//与用法1完全等价,没有任何区别。

3.int * const r=&x;
//声明r为一个常量指针,他指向x,r这个指针的指向不能被修改,但他指向的地址
的内容可以修改.

4.const int * const r=&x;
//综合1,3用法,r是一个指向常量的常量型指针.

三:对于类型检查
可以把一个非const对象赋给一个指向const的指针,因为有时候我们不想从这个
指针来修改其对象的值,但是不可以把一个const对象赋值给一个非const指针,
因为这样可能会通过这个指针改变指向对象的值,但也存在使这种操作通过的合
法化写法,使用类型强制转换可以通过指针改变const对象:
const int r=100;
int *ptr=const_cast <int*> (&r);//C++标准,C语言使用:int* ptr =(int*)&r;

四:对于字......

阅读全文(2878) | 评论:0

CONST(2008-04-17 21:40:00)

摘要:C中CONST的使用:
const是一个C语言的关键字,它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的健壮性,另外,在观看别人代码的时候,清晰理解const所起的作用,对理解对方的程序也有一些帮助。
  虽然这听起来很简单,但实际上,const的使用也是c语言中一个比较微妙的地方,微妙在何处呢?请看下面几个问题。
  
    问题:const变量 & 常量
  
    为什么我象下面的例子一样用一个const变量来初始化数组,ANSI C的编译器会报告一个错误呢?
  
  
  
  const int n = 5;
  int a[n];
  
  
  
    答案与分析:
  
    1)、这个问题讨论的是“常量”与“只读变量”的区别。常量肯定是只读的,例如5, “abc”,等,肯定是只读的,因为程序中根本没有地方存放它的值,当然也就不能够去修改它。而“只读变量”则是在内存中开辟一个地方来存放它的值,只不过这个值由编译器限定不允许被修改。C语言关键字const就是用来限定一个变量不允许被改变的修饰符(Qualifier)。上述代码中变量n被修饰为只读变量,可惜再怎么修饰也不是常量。而ANSI C规定数组定义时维度必须是“常量”,“只读变量”也是不可以的。
  
    2)、注意:在ANSI C中,这种写法是错误的,因为数组的大小应该是个常量,而const int n,n只是一个变量(常量 != 不可变的变量,但在标准C++中,这样定义的是一个常量,这种写法是对的),实际上,根据编译过程及内存分配来看,这种用法本来就应该是合理的,只是 ANSI C对数组的规定限制了它。
  
    3)、那么,在ANSI C 语言中用什么来定义常量呢?答案是enum类型和#define宏,这两个都可以用来定义常量。
  
  
  问题:const变量 & const 限定的内容
  
    下面的代码编译器会报一个错误,请问,哪一个语句是错误的呢?
  
  
  
  typedef char * pStr;
  char string[......

阅读全文(1753) | 评论:0

实时操作系统uC/0S II下TCP/IP协议栈的实现(2008-04-17 10:36:00)

摘要:结合ez80和ARM7两种系统上的具体实现,说明了如何在嵌入式实时操作系统uC/0SII上移植实现LwIP这套TCP/IP协议栈,使uC/0S II成为支持网络的RTOS。 关键词: uC/0S II,TCP/IP,LwIP,网络设备驱动 1 引言 随着嵌入式系统与网络的日益结合,在嵌入式实时操作系统中引入TCP/IP协议栈,以支持嵌入式设备接入网络,成为嵌入式领域重要的研究方向。uC/0S II是近年来发展迅速的一个开放源码实时操作系统,但它只是一个实时的任务调度及通信内核,缺少对外围设备和接口的支持,如没有文件系统、网络协议、图形界面。笔者在多个嵌入式项目的开发过程中,以开源TCP/IP协议栈LwIP为基础,给uC/0S II加上了网络支持。下面就以uC/0S II +LwIP分别在8位MCU ez80和32位MCU ARM7TDMI上的实现为例进行说明。
需要说明的是,笔者使用的ez80系统是Zilog公司的ez80190开发板,自带网络芯片。而ARM7系统是使用笔者参与开发的Skyeye,一个基于GDB的ARM7TDMI指令级软件仿真器。Skyeye小组最近为Skyeye加上了软件模拟的Ne2k兼容网络芯片,可以运行带网络支持的μcLinux和uC/0S II。以下的全部相关程序和代码都可以在Skyeye网站(hpclab.cs.tsinghua.edu.cn/~skyeye/)下载。 2 基于uC/0S II的网络平台概述 嵌入式操作系统uC/0S II是一个公开源代码的占先式多任务的微内核RTOS,其性能和安全性可以与商业产品竞争。uC/0S II的特点可以概括为以下几个方面:公开源代码,代码结构清晰、明了,注释详尽,组织有条理,可移植性好。可裁剪,可固化。内核属于抢占式,最多可以管理60个任务。uC/0S II自1992年的第一版(uC/0S)以来已经有好几百个应用,是一个经实践证明好用且稳定可靠的内核。目前国内对uC/0S II的研究和应用都很多。
TCP/IP是Internet的基本协议,以其实用性、高效性已经成为事实上的工业标准。嵌入式设备要与Internet网络直接交换信息,就必须支持TCP/IP协议。目前嵌入式设备上TCP/IP方案有很多种,但面向低端应用的开源嵌入式网络平台还很少见。
uC/0S II......

阅读全文(2390) | 评论:0

C语言编程规范(2008-03-31 21:07:00)

摘要:C语言编程规范 
〖文章转载或出处〗≡中国电子技术信息网≡ 网址:www.CETINet.com
C语言编程规范(仅供参考) 1. 基本要求
1.1 程序结构清析,简单易懂,单个函数的程序行数不得超过100行。
1.2 打算干什么,要简单,直接了当,代码精简,避免垃圾程序。
1.3 尽量使用标准库函数和公共函数。
1.4 不要随意定义全局变量,尽量使用局部变量。
1.5 使用括号以避免二义性。 2.可读性要求
2.1 可读性第一,效率第二。
2.2 保持注释与代码完全一致。
2.3 每个源程序文件,都有文件头说明,说明规格见规范。
2.4 每个函数,都有函数头说明,说明规格见规范。
2.5 主要变量(结构、联合、类或对象)定义或引用时,注释能反映其含义。
2.7 常量定义(DEFINE)有相应说明。
2.8 处理过程的每个阶段都有相关注释说明。
2.9 在典型算法前都有注释。
2.10 利用缩进来显示程序的逻辑结构,缩进量一致并以Tab键为单位,定义Tab为 6个
字节。
2.11 循环、分支层次不要超过五层。
2.12 注释可以与语句在同一行,也可以在上行。
2.13 空行和空白字符也是一种特殊注释。
2.14 一目了然的语句不加注释。
2.15 注释的作用范围可以为:定义、引用、条件分支以及一段代码。
2.16 注释行数(不包括程序头和函数头说明部份)应占总行数的 1/5 到 1/3 。 3. 结构化要求
3.1 禁止出现两条等价的支路。
3.2 禁止GOTO语句。
3.3 用 IF 语句来强调只执行两组语句中的一组。禁止 ELSE GOTO 和 ELSE RETURN。
3.4 用 CASE 实现多路分支。
3.5 避免从循环引出多个出口。
3.6 函数只有一个出口。
3.7 不使用条件赋值语句。
3.8 避免不必要的分支。
3.9 不要轻易用条件分支去替换逻辑表达式。 4. 正确性与容错性要求
4.1 程序首先是正确,其次是优美
4.2 无法证明你的程序没有错误,因此在编写完一段程序后,应先回头检查。
4.3 改一个错误时可能产生......

阅读全文(1529) | 评论:0

一些实用的单片机c程序(2008-03-31 20:54:00)

摘要:一些实用的单片机c程序  //16进制<->10进制互换程序
 unsigned char d[10];    //用于显示的10位显示缓存  //========================================================
     //16进制to10进制输出子程序:显示数据,起始位,结束位,有无小数点
 //========================================================
 void output(unsigned long dd,unsigned char s,unsigned char
 e,unsigned char dip) {
     unsigned long div;
     unsigned char tm[8],i,j;
     div=10000000;
     for (i=0;i<8;i++) {
         tm[i]=dd/div;
         dd%=div;
         div/=10;
     }
     for (i=0;i<6;i++) {
         if (tm[i]!=0) break;
         tm[i]......

阅读全文(2482) | 评论:0

C 语言编程常见错误(2008-03-22 15:22:00)

摘要:1. 书写标识符时,忽略了大小写字母的区别。
       int main( void )
       {
           int a = 5;
           printf( "%d", A );            return 0;
       }
编译器认为 a 和 A 是两个不同的变量名,而显示出错信息。C 语言规定大写字母和小写字母是不同的字符;而有些编程语言是不分大小写的。习惯上,符号常量名用大写,变量名用小写表示,以增加可读性。
2. 忽略了变量的类型,进行了不合法的运算。
       int main( void )
       {
           float a, b;
           printf( "%d", a % b );            return 0;
       }
% 是求余运算符,a % b 的结果是 a 除以 b 的余数。只有 % 左右两边的操作数都是整型时,才可以进行求余运算。故而上面的程序是错误的,因为 a 和 b 是浮点型变量。
3. 将字......

阅读全文(1611) | 评论:0

位运算(2008-03-10 21:21:00)

摘要:顾名思义,按位运算符允许按照位来操作整型变量。可以把按位运算符应用于任意signed和unsigned整型,包括char类型。但是,它们通常应用于不带符号的整型。 这些运算符的一个常见应用是在整型变量中使用单个的位存储信息。例如标记,它用于描述二进制状态指示符。可以使用一个位来描述有两个状态的值:开或关、男或女,真或假。 也可以使用按位运算符处理存储在一个变量中的几个信息项。例如,颜色值常常记录为三个八位值,分别存储颜色中红、绿和蓝的强度。这些常常保存到四字节变量中的三个字节。第四个字节也不会浪费,包含表示颜色透明度的值。显然,要处理各个颜色成分,需要从变量中分离出各个字节,按位运算符就可以做到这一点。 再看另外一个例子,假定需要记录字体的信息,那么,只要存储每种字体的样式和字号,以及字体是黑体还是斜体,就可以把这些信息都存储在一个二字节的整型变量中,如图3-1所示。 图3-1 把字体数据存储在2个字节中 可以使用一位来记录字体是否为斜体—— 1表示斜体,0表示一般。同样,用另一位来指定字体是否为黑体。使用一个字节可以从多达256种不同的样式中选择一个,再用另外5位记录最多32磅的字号。因此,在一个16位的字中,可以记录四个不同的数据项。按位运算符提供了访问和修改整数中单个位和一组位的便利方式,能方便地组合和分解一个16位的字。 3.3.1 移位运算符 移位运算符可以把整型变量中的内容向左或向右移动指定的位数。移位运算符和其他按位运算符一起使用,可以获得前面描述的结果。>>运算符把位向右移动,<<运算符把位向左移动,移出变量两端的位被舍弃。 所有的按位操作都可以处理任何类型的整数,但本章的例子使用16位的变量,使例子较为简单。用下面的语句声明并初始化一个变量number: unsigned short number=16387U; 如第2章所述,不带符号的字面量应在数字的最后添加字母U或u。 在下面的语句中,对这个变量的内容进行移位,并存储结果: unsigned short result = number <<2; //Shift left two bit positions 移位运算符的左操作数是要移位的值,右操作数指定要移动的位数。图3-2列出了该操作的过程。 图3-2 移位运算 从图3......

阅读全文(3051) | 评论:0

c++位运算(2008-03-10 21:13:00)

摘要:前言  
  看到有些人对位运算还存在问题,于是决定写这篇文章作个简要说明。  
   
  什么是位(bit)?  
   
  很简单,位(bit)就是单个的0或1,位是我们在计算机上所作一切的基础。计算机上的所有数据都是用位来存储的。一个字节(BYTE)由八个位组成,一个字(WORD)是二个字节或十六位,一个双字(DWORD)是二个字(WORDS)或三十二位。如下所示:  
   
      0   1   0   0   0   1   1   1   1   0   0   0   0   1   1   1   0   1   1   1   0   1   0   0   0   1   1   1   1   0   0   0  
  |   |                             |                               |                               |                   &nb......

阅读全文(1792) | 评论:0

LPC213X硬件SPI接口LCD19232显示C++代码(2008-02-22 22:31:00)

摘要:/*-------------------------------------------------------------------- LPC213X硬件SPI接口LCD19232显示C++代码 HotPower@126.com --------------------------------------------------------------------*/ //__inline
LcdObj::LcdObj(void)
{
  LcdSpiInit();//SPI初始化
  LcdInit();
} //__inline
void LcdObj::LcdSpiInit(void)
{
/* 设置MOSI 和SCK 及SS 为输出,其他为输入 */
  LCDPORT->IODIR |= (1 << LCDCS);
  LCDPORT->IOCLR = (1 << LCDCS);
/*
  LCDPORT->IODIR |= (1 << LCDSCK)| (1 << LCDSID);//设置输出方式
  LCDPORT->IOSET = (1 << LCDSCK) | (1 << LCDSID);
*/
  POWER->P_CONP |= (1 << PCSPI0);
  PINSEL->PIN_SEL0 |= ((P0_4_SCK0 << P0_4_PINSEL) | (P0_6_MOSI0 << P0_6_PINSEL));
//  SPI->SPI_SPCCR = 0x168;              // 设置SPI时钟分频
  SPI->SPI_SPCCR = 0x52;     &nb......

阅读全文(2257) | 评论:0