C语言软件编程经验交流_第1页
C语言软件编程经验交流_第2页
C语言软件编程经验交流_第3页
C语言软件编程经验交流_第4页
C语言软件编程经验交流_第5页
已阅读5页,还剩62页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、C语言软件编程经验交流C语言软件编程经验交流C 语言,不会讲太多其他高级语言比如 C+, JAVA, PYTHON 等等,刚进实验室的学生我的建议是先学好 C 语言,掌握项目开发中软件的开发目的,开发流程,测试流程等。 注意,做这个报告的目的是希望大家能够开发出高效的 C 程序,而不是让大家开发出复杂高难度高技巧的 C 报告目的提纲一、C 语言基础二、内存管理三、常用技巧四、调试五、示例开发软件工欲善其事,必先利其器 -论语牢牢打好基础,紧紧抓住核心,真正实现目的 -深入学习科学发展观编辑软件:,VS20XX 编程辅助软件:msdn功能性辅助软件:vc assistant,numega bou

2、nds checker, intelvtune,source insight推荐的资料: 高质量 C/C+ 编程指南(林锐)、 Windows 核心编程、linux 高级程序设计一、C语言基础在 C 语言中使用的词汇分为六类:标识符,关键字,运算符,分隔符,常量,注释符。1.1.1 C 语言词汇标识符只能是字母、数字、下划线组成的字符串,并且其第一个字符必须是字母或下划线。以下标识符是合法的:a, x, _3x, BOOK_1, sum5以下标识符是非法的:3s 以数字开头; s*T 出现非法字符*; -3x 以减号开头;(1)标识符一、C语言基础在使用标识符时注意以下几点:标准 C 不限制标

3、识符的长度,但它受各种版本的 C 语言编译系统限制,同时也受到具体机器的限制;在标识符中,大小写是有区别的。例如 BOOK 和 book 是两个不同的标识符;标识符虽然可由程序员随意定义,但标识符是用于标识某个量的符号。因此,命名应尽量有相应的意义,以便阅读理解,作到“顾名思义”。 int ImgWidth;(1)标识符一、C语言基础1、匈牙利命名法:开头字母用变量类型的缩写,其余部分用变量的英文或英文的缩写,要求单词第一个字母大写。int iMyAge; “i”是int类型的缩写;char cMyName10; “c”是char类型的缩写;float fManHeight; “f”是floa

4、t类型的缩写;2、驼峰规则:又叫小驼峰式命名法。第一个单词首字母小写,后面其他单词首字母大写。int myAge;char myName10;float manHeight;3 . 帕斯卡命名法:又叫大驼峰式命名法。每个单词的第一个字母都大写。int MyAge;char MyName10;float ManHeight;一、C语言基础关键字是由 语言规定的具有特定意义的字符串,通常也称为保留字。用户定义的标识符不应与关键字相同。C 语言的关键字分为以下几类:(2)关键字一、C语言基础类型说明符 用于定义、说明变量、函数或其它数据结构的类型。如 char,short,int,double 等语

5、句定义符 用于表示一个语句的功能。如 for, if, else, while, switch 等。预处理命令字 用于表示一个预处理命令。如 #define #pragma 等。C 语言中运算符与变量,函数一起组成表达式,表示各种运算功能。运算符由一个或多个字符组成,如 ,=,& 等。(3)运算符(4)分隔符在 C 语言中采用的分隔符有逗号和空格两种。一、C语言基础(5)常量C 语言中使用的常量可分为数字常量、字符常量、字符串常量、符号常量、转义字符等多种。比如 char *p = “hello world”; C 语言中的常量是不接受程序修改的固定值。(6)注释符C 语言的注释符是以

6、“/*”开头并以“*/”结尾的串,C+ 中使用“/”注释所在行。一、C语言基础什么是字节对齐,为什么要字节对齐?1.1.2 字节对齐一、C语言基础(1)什么是字节对齐?现代计算机中内存空间都是按照 byte 划分的,从理论上讲对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。一、C语言基础(2)为什么要字节对齐?对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况, 但

7、是最常见的是如果不按照适合其平台的要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个 int型(假设为 32 位)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要 2 个读周期,并对两次读出的结果的高低 字节进行拼凑才能得到该int数据。一、C语言基础(3)大小端(例程) 在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。对于位数大于 8 位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。 所谓的大端模式,是指数据的低位保存在内存的

8、高地址中,而数据的高位,保存在内存的低地址中;所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中一、C语言基础(3)大小端(例程)写一个 C 函数,若处理器是 Big_endian 的,则返回 0;若是 Little_endian的,则返回 1int checkCPU三 union w int a; char b; c; c.a = 1; return (c.b = 1); 一、C语言基础(3)大小端(例程)采用 Little-endian 模式的 CPU 对操作数的存放方式是从低字节到高字节,而 Big-endian 模式对操作数的存放方式是从高字节到低字节

9、序是所有成员都从低地址开始存放。联合体 union 的存放顺序是所有成员都从低地址开始存放。一、C语言基础/ 作者版权版本说明,头文件声明,全局变量,函数声明,预处理块#include #include ”global.h”void output三; / 子函数声明int main(int argc, char *argv)int i,j;unsigned char *data; /定义局部变量/ 分配数据空间,分配在堆上data = (unsigned char *)malloc(1000*sizeof(unsigned char);for(i) / 调用子函数output三;/ 释放分配空

10、间free(data);data=NULL;void output三一、C语言基础 #ifndef GRAPHICS_H (作用:防止被重复引用)#define GRAPHICS_H#include. (作用:引用标准库的头文件)#include. (作用:引用非标准库的头文件)void Function1(.); (作用:全局函数声明)class Box (作用:类结构声明);#endif1.2.1 头文件一、C语言基础在头文件中,用 ifndef/define/endif结构产生预处理块,用 #include 格式来引用库的头文件。头文件一般由三部分内容组成:1.2.1 头文件头文件开头处

11、的版权和版本声明;预处理块;函数和类结构声明等。一、C语言基础头文件的主要作用在于调用库功能,对各个被调用函数给出一个描述,其本身不包含程序的逻辑实现代码,它只起描述性作用,告诉应用程序通过相应途径寻找相应功能函数的真正逻辑实现代码。用户程序只需要按照头文件中的接口声明来调用库功能,编译器会从库中提取相应的代码。1.2.1 头文件一、C语言基础 注意:1) 在 .h文件中声明的函数,如果在其对应的 .c 文件中有定义,那么我们在声明这个函数时,不使用 extern 修饰符, 如果反之,则必须显示使用 extern 修饰符; 2) 不要在 .h 文件中编写实现代码,不要 #include “.c

12、”文件。1.2.1 头文件一、C语言基础所有全局变量尽量以 g_ 开头,并且尽可能声明成 static 类型;尽量杜绝跨文件访问全局变量.如果的确需要在多个文件内访问同一变量,应该由该变量定义所在文件内提供 GET/PUT 函数实现;全局变量必须要有一个初始值,全局变量尽量放在一个专门的函数内初始化;如调用全局变量的函数少于三个,考虑改为局部变量实现。1.2.2 谨慎使用全局变量一、C语言基础在实际的软件项目中,每个人负责的可能只是一个模块,对全局变量的使用没有小程序那样简单,在使用全局变量的时候更要谨慎,跨模块调用的全局变量使用时都需要申请,而且定义必须明确。1.2.2 谨慎使用全局变量一、

13、C语言基础void main(int argc, char *argv)1.2.3 main函数一、C语言基础命令行界面的程序,通常都需要输入命令行参数帮助程序执行。假定有一个可执行程序名为 。运行该程序的的命令行如下:带命令行参数是同一行中的附加项: c TEST其中 c 和 TEST 就是命令行参数。C程序通过使用 main三 的参数来读取这些附加参数。main(int argc, char*argv) 这个函数中两个参数的意义:argc 记录的是命令行中输入参数的数目; argv 是一个拥有 argc 个元素的字符串数组,每个元素保存一个命令行中输入的参数。1.2.3 main函数一、C

14、语言基础#include int main(int argc, char * argv) int i; for (i=0; i argc; i+)printf(Argument %d is %s.n, i, argvi); return 0; 1.2.3 main函数一、C语言基础下面的程序演示 argc 和 argv 的使用: Argument 0 is hello.exe. Argument 1 is a. Argument 2 is b. Argument 3 is c. Argument 4 is d. Argument 5 is e. 1.2.3 main函数一、C语言基础运行结果:

15、假如上述代码编译为 ,那么运行:hello.exe a b c d e 1.2.3 main 函数一、C语言基础在这个例子中,argc 的值为 6,命令行一共输入了六个参数:“hello.exe”、“a”、 “b” 、 “c” 、 “d” 、“e” 对应程序输入为: ,argv1:a, argv2: b , argv3:c ,argv4:d argv5:en需要注意的是若输入参数作为数值使用时,使用 atoi atof进行字符转换 看例程一、C语言基础1.3 代码编写规范从书写清晰,便于阅读,理解,维护的角度出发,在书写程序时应遵循以下规则:一个说明或一个语句占一行。if,for,while,

16、do占一行,执行语句放后面并且使用大括号,多用对齐。用 括起来的部分,通常表示了程序的某一层次结构。一般与该结构语句的第一个字母对齐,并单独占一行。低一层次的语句或说明可比高一层次的语句或说明缩进若干格后书写。以便看起来更加清晰,增加程序的可读性。在编程时应力求遵循这些规则,以养成良好的编程风格。多写注释,合理的使用注释可以让你的程序可读性更高。一、C语言基础另外一些编程风格说明:程序块要采用缩进风格编写,缩进少使用空格键;对齐多使用TAB键,少使用空格键;逗号、分号只在后面加空格。 int a, b, c; 比较操作符, 赋值操作符“=”,“+=”,算术操作符“+”,“%”,逻辑操作符“&a

17、mp;”,“&”,位域操作符“”,“.”前后不加空格。 p-id = pid; /“-”指针前后不加空格 if、for、while、switch等与后面的括号间应加空格,使if等关键字更为突出、明显。 if (a = b & c d) 一、C语言基础一、C语言基础1.4 命名规则使用匈牙利命名法,标识符应直观意思明确尽量使用缩写,如 int iImgWidth; 不要使用大小写来区分变量,如 int x,X; 局部变量不要与全局变量同名; 常量使用大写字母,合理使用前缀,静态变量加前缀s_,全局变量加前缀 g_。一、C语言基础1.5 表达式 注意优先级的的高低以及结合顺序,多使

18、用括号确定优先级一、C语言基础1.5 表达式注意if常用的条件判断情况: 布尔变量 if(flag) if(!flag) 整型变量 if(flag=0) if(flag!=0) 浮点变量 if( abs(x-0) 1e-5) 指针变量 if(p=NULL)if(p!=NULL) if 语句一、C语言基础1.5 表达式注意以下几点:多重循环中,尽量将循环少的放在外层循环for(i=0; iN;i+),循环执行 N 次,最大执行到 i=N-1,i最后执行完等于Nswitch 的每个 case 都加上 break,最后加上 default 尽量少用 goto 循环语句从静态存储区域分配,在程序编译的

19、时候就已经分配好,整个运行期都存在。如全局变量和 static 变量。从栈上创建,从函数创建开始存在,函数结束就释放,效率高,但是分配大小有限。如函数内部变量。从堆上分配,也称动态内存分配。使用 malloc 分配,需要手动 free 释放。使用灵活,容易出问题。C语言中内存分配区域:二、内存管理二、内存管理2.1 常见内存错误没有分配直接使用或者分配未成功却使用了它;没有初始化或者归零就直接使用(分配内存后系统默认值不一定是 0);使用时内存访问越界,使用完忘记释放内存,造成内存泄漏;对已分配内存的指针进行赋值操作,原来分配内存区域丢失,内存泄漏;释放了内存却继续使用,指针在释放后并不是变为

20、 NULL,仍然指向原来地址,成为“野指针”。二、内存管理2.2 指针与数组数组在栈上和静态存储区域创建,其地址与容量分配后不可改变,但内容可以改变;指针的特征是“可变”,用于分配动态内存区域;不能直接对数组名进行复制和比较,使用 strcpy 和 strcmp;指针存储的是动态内存区域的地址,可以直接传递地址,当对两块动态内存区域复制或比较时使用memcpy 和 memcmp;数组的大小,需要加上最后面的0,可以使用 sizeof 获得;指针使用 sizeof 获得的是指针变量的字节数;需要注意的是当数组作为函数参数传递时,自动退化为该类型的指针。二、内存管理2.2 指针与数组例子:二、内存

21、管理2.3 指针指针的本质是地址,指针变量本身作为普通寄存器变量被存储,特别是该寄存器地址内存储的是另一个寄存器地址,该寄存器地址内存储的数据是指针指向的数据。栈mainint i=200;char *p;0 x123456假设已给p分配空间0 x12 3456p=0 x123456i=2000 x1234560 x123452100*p=1000 x20XX120 x20XX16&p=0 x20XX16&i=0 x20XX20200栈二、内存管理2.3 指针malloc 在堆上分配动态内存区域,需要指定分配区域的大小,以字节作为单位。 p = (char *)malloc(1

22、*sizeof(char);/分配到0 x123456,存储在栈地址0 x20XX16的内存地址中 *p=100;/修改0 x123456中数值为100/free将分配的动态内存区域释放free(p);/虽然0 x123456该地址被标志为已释放,但是p内存储的仍然是 0 x123456,p成为野指针p=NULL;/将0 x20XX16内数据改为0 x00,该地址不可访问 malloc 与 free:二、内存管理当子函数中使用指针时,子函数执行结束指针没有 free 掉,此时指针变量释放了,不代表它所指向的内存自动释放了。当内存被释放时,不代表指针不存在了或者指针成为 NULL 指针。需要查找

23、程序内存泄漏。2.3 指针 需要注意的几点:三、常用技巧3.1 宏的使用#define ceil_div(x, y) (x + y - 1) / y宏执行的是简单的替换作用,需要注意由操作符优先级引起的问题,多加括号。那么 a = ceil_div( b & c, sizeof(int) );将被转化为: a = ( b & c + sizeof(int) - 1) / sizeof(int);由于+/-的优先级高于&的优先级,那么上面式子等同于:a = ( b & (c + sizeof(int) - 1) / sizeof(int);为了避免这种情况发生,应

24、当多写几个括号:#define ceil_div(x, y) (x) + (y) - 1) / (y)三、常用技巧3.1 宏的使用 函数变宏每行代码最后都加行连接符“”,即使是空行也要加“”,最后一行代码后面不需要加“”,每行“”最后不能有多余字符或者空格,返回的是最后一条语句的执行结果。可以在宏函数内定义变量,可以使用if等语句,可以在宏内调用其他宏,可以使用指针。函数变宏可以加快程序运行速度。看例子三、常用技巧3.2 运行时间测量程序运行过程中,我们经常需要统计程序运行时间。下面给出示例:#include main三clock_t begin,end;begin = clock三;end=

25、 clock三;double duration; duration = (double)(end - begin ) / CLOCKS_PER_SEC; printf( “Time is %2.1f secondsn, duration ); / #define CLOCKS_PER_SEC 1000/ 事实上end begin获得的是毫秒计数三、常用技巧3.2 运行时间测量Time三 函数是获得当前系统时间用的,一般不用于计时。当程序运行时间太短时,可以使用多次执行的办法来获得。可以使用更精确的运行时间计数函数:“QueryPerformanceCounter三”“QueryPerforma

26、nceFrequency三”三、常用技巧 随机数生成:#include #include #include void main( void ) int i; /* Seed the random-number generator with current time so that * the numbers will be different every time we run. */ srand( (unsigned)time( NULL ) ); /* Display 10 numbers. */ for( i = 0; i 10;i+ ) printf( %6dn, rand三 ); S

27、rand是产生伪随机序列的种子,种子一样产生的伪随机序列一样。 RAND_MAX0 x7fffffff j=(int)(*rand三/(RAND_MAX+1.0) 产生一个0到之间的随机数三、常用技巧3.3 文件操作 文件的打开与关闭 文件在进行读写操作之前要先打开,使用完毕要关闭。打开文件实际上是建立文件的各种有关信息,并使文件指针指向该文件,以便进行其它操作。关闭文件则断开指针与文件之间的联系,也就禁止再对该文进行操作。 在语言中,文件操作都是由库函数来完成的。fp = fopen(“filename”,“r”); 三、常用技巧 对于文件使用方式有以下几点说明: 文件使用方式由r,w,a,

28、b,t,+六个字符拼成,各字符的含义是: r(read): 读 w(write): 写 a(append): 追加 b(binary): 二进制文件 +: 读和写 凡用“r”打开一个文件时,该文件必须已经存在,且只能从该文件读出。 用“w”打开的文件只能向该文件写入。若打开的文件不存在,则以指定的文件名建立该文件,若打开的文件已经存在,则将该文件删去,重建一个新文件。 三、常用技巧if(fp=fopen(“readme.txt,rb)=NULL) printf(nerror on open c:hzk16 file!); exit(1); 若要向一个已存在的文件追加新的信息,只能用“a”方式打

29、开文件。但此时该文件必须是存在的,否则将会出错。在打开一个文件时,如果出错,fopen将返回一个空指针值NULL。在程序中可以用这一信息来判别是否完成打开文件的工作,并作相应的处理。三、常用技巧 文件的读写对文件的读和写是最常用的文件操作。在语言中提供了多种文件读写的函数: 字符读写函数 :fgetc和fputc 字符串读写函数:fgets和fputs 数据块读写函数:fread和fwrite 格式化读写函数:fscanf和fprinf行操作。 三、常用技巧 文件的读写在文件内部有一个位置指针,用来指向文件的当前读写字节。在文件打开时,该指针总是指向文件的第一个字节。使用fgetc 函数后,该

30、位置指针将向后移动一个字节。应注意文件指针和文件内部的位置指针不是一回事。文件指针是指向整个文件的,文件内部的位置指针用以指示文件内部的当前读写位置,每读写一次,该指针系统自动向后移动。三、常用技巧 计算文件长度的程序示例long filesize(FILE *stream) long curpos, length; curpos = ftell(stream); fseek(stream, 0L, SEEK_END); length = ftell(stream); fseek(stream, curpos, SEEK_SET); return length;进行二进制文件读写时,打开方式后

31、面加“b”四、调试编程出现error时,从第一个error处开始解决错误,可能是很小的书写错误引起的。warning也需要关注,有时候会导致程序运行错误发生。程序出现BUG时,单步跟踪,查看变量,查看内存,查看栈调用,可以边编辑边跟踪。加入合适的断点,使用条件断点。程序调试结束后需要查找内存泄露,规范代码书写。使用assert,只有条件满足才继续向下执行,在release下不会编译该语句。程序编写完成不一定是完全正确的,需要进行测试并进行跟踪调试。四、调试4.1 条件断点我们在调试的时候希望程序在某个断点处只有在满足一定的条件下中断,在不满足条件的时候正常运行,可以为程序调试带来极大的便利。

32、示例四、调试4.2 内存泄漏查找 养成好的代码写作规范,掌握内存管理概念,减少不规范代码内存泄漏可能性。是否内存泄露:运行可执行文件,使用任务管理器查看内存占用情况是否一直增加。比较简单但是显示不一定精确。使用NumegaBounderChecker软件查找,程序中加入exit(0)强制中断,Debug至该代码行程序异常中断时查看内存泄露报告。 示例四、调试4.3 watch 跟踪调试时多使用watch窗口,在watch窗口内可以进行有限运算,注意watch 运算带来的影响。 示例四、调试4.4 C 程序优化首先要确定优化目标,然后寻找优化方法。查找程序运行瓶颈,使用Intel Vtune查看

33、各部分运行时间,一步步进行优化。现在CPU,GPU发展方向都是多核,并行计算越来越方便,为优化提供了更多解决方案。任务级并行,使用多线程发挥多核优势。 指令级并行,使用MMX,SSE,SSE2等指令集。 参看Vtune使用指南五、示例5.1 软件设计算法思想,思路清楚,注意细节质量控制,代码高效,风格良好测试调试,测试全面,调试认真软件设计过程关键部分:在编写软件程序之前,首先要明确你要解决的问题,软件只是思想的实现,不能通过编程来获得思想。所以在编写之前就需要对问题有透彻的理解,对解决问题的方法有清晰的思路,要考虑到可能遇到的所有问题,同时要考虑到软件的可靠性稳定性等。五、示例5.1 软件设计在编写软

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论