热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Unix(Linux)C编程问题精粹

Unix(Linux)C编程问题精粹--Linux通用技术-Linux编程与内核信息,下面是详情阅读。
对于C语言,有人认为它已经落伍了.对于这个问题,仁者见仕,智者见智.的确,C++比C有更强大的诸多优势.但C++是建立在C之上的.这也是Herbert Schildt所著的<>在全世界畅销不衰的原因.更何况,要深入学习LINUX就必需要有相当的C功底.(这也是我搜集整理本文的根由:-)
现结合个人在编程中的体会,为使新手少走弯路,为老手锦上添花,因此无论你是使用C或C++编程,也无论你是程序设计的初学者还是成熟的专业人员,均会发现,本文将会对你有所收益.当然,我尽力写得清晰易懂,又不古板.

=======================================
|版权声明:你可以自由复制与分发本文档 |
|如果你要修改本文档或提出更好建议,请 |
|先通知文章的作者。而不要仅在公告栏中 |
|贴出。因为作者可能漏看。无论如何,都 |
|须保留本声明。 |
| |
| |
| pjbright@telekbird.com.cn |

=======================================

文章目录
第一章:前言
第二章:约定
第三章:开始任务
第四章:使用lint
第五章:使用make
第六章:优质无错编程
第七章:调试技术
第八章:其它更好的文档

第一章:前言


你可以在forum.linuxaid.com.cn上获得此帖的文本.而其HTML版本正在赶制之中......
如果你是在一个月之后看到本文,那么此文或许已经更新了:-)


第二章:约定

专业的源程书写风格.
先看看世界级C大师的源程书写风格.如 Steve Maguire 就有许多不错的建议.

[]倡导使用易于理解的"匈牙利式"的命名约定.
所有的字符变量均以ch开始; 如: char ch_****;
所有的字节变量均冠以b; 如: byte b_****;
所有的长字变量均冠以l; 如: long l_****;
所有的指针变量均冠以P; 如: char *p_ch_****;
建议类型派生出的基本名字之后加上一个以大写字母开头的"标签".如:
分析 char **ppchMydata;
其让人一眼就能看出它代表一个指向字符指针Mydata的指针.
"匈牙利式"命名的最大不足是难念:-(( .但相对于不是总统演讲稿的C源程来说,这又算得了什么?想想看以下的数据命名:
char a,b,c;
long d,e,f;
.
.
.
(反正我是不会再看下去了...)

[]倡导规范书写.
如果你思如泉涌,而不去也不及顾虑书写格式,那也没关系.在将其交出去之前,用cb命令格式化你的源程.虽然源程的格式不会影响到你编译结果的正确性,但切记,能让其他的程序员能轻松地阅读它.否则没人会理你的.
关于cb命令的更多用法,可以用man cb来参考其手册页.
当然除了cb之外,还有更多更好的.但cb是你在任何UNIX(LINUX)上都找得到的.更何况它并不差.


第三章:开始任务

开始任务之前,先做个深呼吸!



[]其他文档你准备好了吗?
你是不是除了C源程之外一无所有了吗?兵马未动,粮草先行.你必须先清楚该程序所要完成的功能.在开始写程序之前,对程序的功能应有规范说明.书写规范书和确知程序功能的一个方法是先编写相应的操作手册.如果你是一人单干,劝你首先写需求书.切记切记,这对你意味着事半功倍的大好事.
一个实例:我计划为本行的信贷子功能模块打一个补丁.我用10周的时间用来写规划书,需求书,操作流程,使用说明等等文档.之后用2周的时间编写程序,在初步测试(1周)后递交给各信贷部门测试使用.然后根据反馈的信息再更改相应文档,并根据文档修改源程.6个月后发布正式版.

[]一定该遵循ANSI标准吗?
如果你仅使用ANSI的标准首标文件,恭喜你,你的程序有着全世界范围内的广泛支持和兼容.光明无限.但你必须在通用与专用之间做出取舍,对不起,我帮不了你.
我的原则是:核心用ANSI,界面按需而取.这样在转换平台时仅需另编用户界面而已.实用至上嘛.
附:ANSI 标准C头文件






是不是很寒酸?

[]再续前缘?
在得到新任务之后并在开始该新任务之前应马上回想有哪些是曾经拥有的.旧调重弹远比另起炉灶来的高效与环保.

[]是否该有自已的库?
我的答案是应该有自已的特色库,并与ANSI兼容.与3.8不同的是,你仅需在源程序之后附上自已的专用库就可以了.其次在有了自已的库后,源码会很精炼的.不用去羡慕别人了吧.

[]要学会条件编译.注意你的平台特性.(高手的标志?)
除非你确定你要写的程序是在某特定的OS特定的硬件平台而量身定做.否则应注意数据类型的长度,精度都是不同的,不要想当然.有时甚至是不同的编译器的差异都要考虑考虑.

....
....(欢迎您来充实此处空白)
....

好了,在任务中,又有哪些细节呢?

[]我是不是葛郎台?
不要那么吝啬.在源程序中加入详尽的注释以使自己和他人即使在许多年以后仍能读明白它是什么样的程序.
用注释行分离各个函数.

[]删除不需要的代码时要小心.
一个好建议是:使用#ifdef DEL,而不是简单地注释掉甚至是粗暴地直接dd.如果你是使用/* ... */,但一旦要删除的代码有很多行,或注释中以有注释时,这就可能不那么好使了.

[]如何给源程序文件命名?
表现特色且不与任何原有应用名相同.一个简单地方法就是试试看,系统有什么样地反应?

[]一次只修改一个地方.

[]一次只编写一个单一功能的函数。

[]编写通用程序.
只有当程序编写完,并且完成了所需要的性能要求之后,再反过头来优化该程序.

[]不要使用a.out作为结果.你大可以使用与源程相同的可执行文件名.

[]是否一定要用VI编辑?
LINUX下有许多专用编程编辑器.它们能使你有更高的效率和更低的低级输入错误,但我还是要劝你至少要熟练掌握VI.毕竟VI遍地开花.

[]协同作业.请相信,你不是在孤军作战.因此,你有必要熟练掌握一些其它的工具.如


....
....(欢迎您来充实此处空白)
....


第四章:使用lint

lint没有你想象中的那样糟糕.相反,一旦源程序形成了没有LINT错误的形式,将很容易保持下去,并享受到如此而带来的好处.

[]在cc(gcc)之前就应使用LINT.
lint是一语法检查程序,对于这个多嘴的婆婆来说,你应有足够的耐心.虽然你知道自已在干什么,但在CC之前使用LINT总是一个好习惯.

[]lint有哪些特色?
在编译之前使用lint的重要原因是LINT不但能发现ANSI C中的语法错误,而且也能指出潜在的问题或是难于移植于另一机器的代码问题.除了能指出简单语法错误之外,LINUT还能基于以下原因指出另外的错误:
A.无法达到的语句.
B.没有进入循环.
C.没有被使用的变量.
D.函数参数从未使用.
E.没有赋值之前自动使用参数.
F.函数在有些地方有返回值,但在其他地方不返回.
G.函数调用在不同地方使得参数个数不同.
H.错误使用结构指针.
I.模糊使用操作符优先级.
呵呵呵,挺有用的吧!

[]如何控制LINT的输出?
有时LINT会有一大屏一大屏的警告信息.但似乎并未指出错误.为了找出潜在的错误则需费心费力地浏览这些大量的警告信息.
但如果你的程序会分出几个独立的模块,在初级启动LINT时不要用可选项.当对这些模块进行更改或扩充时,可以忽略与代码无关的某些警告.为此可用以下选择项:
-h 对判别是否有错,类型是否正确不给出启发式测试.
-v 不管函数中没有定义的参数
-u 不管被使用的变量和函数没有定义或定义了但没有使用.

[]干脆,在程序中插入指令来影响LINT运行.它看样子有些像注释.
/*NOTREACHED*/ 不可达到的代码不给信息说明.
/*VARARGSn*/ 函数的变量个数不作通常的检查,只检查开始n个参数的数据类型.
/*NOSTRUCT*/ 对下一个表达式不作严格类型检查.
/*ARGUSED*/ 下一函数中,不给出没被使用参数的警告信息.
/*LINTLIBRARY*/ 置于文件的开头,它将不给出没被使用函数的警告信息.

关于LINT的更多用法,请用man lint来获知.


第五章:使用make

[]什么是make?

Unix(Linux)是一个天生的开发平台,我为此感到高兴.make是一个强力的工具.它能自动跟踪相互依赖的源代码块并组成一程序,使得很容易建立一可执行程序.Make就是这种有依赖关系的部分和代码之间所作的规格说明.


[] 所有的程序都要使用make?
是的.尽管你只有几个简单的模块,但你需要有一种结构来支持它从简单走向复杂.除非你的程序已经盖棺定论.

[]Makefile由哪些组成?
Makefile由以下几个部分组成:

注释.
^^^^
使用#符号插入.make将忽略#之后的任何内容以及其后的RETURN键.

变量.
^^^^
make允许定义与SHELL变量类似的有名变量.比如,你定义了SOURCES=prog.c,那么该变量的值$(SCOURES)就包含了源文件名.

依赖关系.
^^^^^^^^
左边是目标模块,后接一冒号.再接与该模块有依赖关系的模块.

命令.
^^^^
以TAB键开始(即使用相同数量的空格也不能代替它).


[]Makefile示例
下面介绍一个简单的示例来说明make的用法.假设你的程序有两个源文件main.c和myc.c,一个位於子目录include下的头文件myhead.h,一个库由三个源文件myrout1.c,myrout2.c,myrout3.c产生.
其makefile文件为:
#一个基本的MAKEFILE文件.
#其中包括个人的头文件和个人库.
HEADERS=include/myhead.h
SOURCES=main.c myc.c
PRODUCT=$(HOME)/bin/tool
LIB=myrout.a
LIBSOURES=myrout1.c myrout2.c myrout3.c
CC=cc
CFLAGS=-g
all:$(PRODUCT)
$(PRODUCT):$(SOURCES)
$(CC)$(CFLAGS) -o $(PRODUCT)$(SOURCES)
lint:$(PRODUCT)
lint $(SOURCES)$(LIBSOURCES)
哈哈,挺象SHELL编程的.如果你与我一样使用LINUX下的gcc,那么只要把上面的CC=cc改为CC=gcc即可.怎么样,想来一个更复杂点的吗?

[]一个更为复杂的Makefile
你是否注意到,在上例中,只要启动make,就会重新编译所有源代码.
如果你能看懂以下的makefile,恭喜恭喜,你通关了.
#一个更为复杂的makefile
HEADERS=include/myhead.h
SOURES=main.c myc.c
OBJECTS=main.c myc.c
PRODUCT=$(HOME)/bin/tool
LIB=myrout.a
LIBSOURCES=myrout1.c myrout2.c myrout3.c
LIBOBJECTS=$(LIB)(myrout1.o)$(LIB)(myrout2.o)$(LIB)(myrout3.o)
INCLUDE=include
CC=cc
CFLAGS=-g -Xc
LINT=lint
LINTFLAGS=-Xc
all:$(PRODUCT)
$(PRODUCT):$(OBJECTS)$(LIB)
$(CC)(CFLAGS)-o$(PRODUCT)$(OBJECTS)$(LIB)
.c.o: $(HEADERS)
$(CC)$(CFLAGS) -c I$(INCLUDE)$<
$(LIB):$(HEADERS)$(LIBSOURCES)
$(CC) $(CFLAGS) -c $(?:.o=.c)
ar rv $(LIB) $?
rm $?
.c.c:;
lint: $(PRODUCT)
$(LINT)$(LINIFLAGS)$(SOURCES)$LIBSOURCES)




第六章:优质无错编程


亲爱的,检查一下,你是否注意到了以下的细节?也就是说,你是否是一个合格的,能编写优质无错代码的程序员?要永远记住,编写无错代码是程序员的责任,而不是测试员.(摘录于本人的"细节页",因此本节将永远不会保持完整,欢迎您来充实她)

[]所有程序员至少出现过的一个错误:
if(a=3){......}如果a等于3,那么......
你至少要养成这样的习惯:当判断一个变量与一个常量是否相等时,将常量写在前面.这样即使你一不小心写成这样:if(3=a){......}在cc 之前就可以很容易发现它.


[]老调重弹:逻辑操作符的优先权.
我不愿多嘴.总之,如果你一定要编写如下代码时:
if(a&0x1&&b&0x2){......}
你的手头最好有一本详尽的指南.或者你是这方面的专家.

[]尽量不使用int数据类型.
这仅是一个忠告.你大可使用char,short,long数据类型.若干年以后,当你成长为高手之时,你会发现此时我的良苦用心.

[]对于非整型函数一定要完整定义.
如 long float jisuan(char chArr[],int chNum)
{ long float lMydata;
...
...
return(lMydata); }

[]对于非整型函数的输入要当心.
如 long float lfNum;
...
...
scanf("%lf",&lfNum);

[]float 型的有效数字为7位.当多于7位时,第8位及以后的位将不准确,可以将其定义为long float型.

[]文件的输入出尽量采用fread fwrite函数.只有当另有用途时才用fprintf fscanf 函数.

[]对于数组及字符串的比较操作时要确认以''结束.


第七章:调试技术


调试技术在本文中不太好说,之所以将其独立成章是想套用M$的老话:"在下一版本中将会做得更好":-((.其实这类文章在全国各大BBS上满天飞.

在此我只想说说程序员的应尽职责之一:在程序中使用断言.
~~~~
[]既要维护程序的交付版本,又要维护程序的调试版本,这时可以利用断言补救.

[]要使用断言对函数参数进行确认.

[]要从程序中删除无定义的特性,或者在程序中使用断言来检查出无定义特性的非法使用.

[]不要浪费别人的时间,详细说明不清楚的断言.

[]消除所做的隐式假定,或者利用断言检查其正确性.

[]利用断言来检查不可能发生的情况.

一个实例:我在我的源程序中都使用断言.在本人所编制的全国电子汇兑模糊检索功能模块测试中,前台人员气喘吁吁地告诉我,屏幕上出现了不认识的英文.我说最前面的是哪几个数字,然后根据此数字查阅断言文档,原来是前日日终未正常结束,经查只有半个库.这种情况极少发生,但不是不可能发生.使用断言能及时正确地判别是否是程序的错误还是外部的因素.因此使用断言,是将错误消灭在发生错误之前的一个极其重要的手法.这也是判断一个程序员是否具备良好素质的一个方面.


第八章:其它更好的文档


<> Kenneth H. Rosen ...etc.
<> UNIX Software Operation.
<> Herbert Schildt.
<> Steve Maguire.
<> Daniel Barlow.
<> 谭浩强.

NOTE:本人的<>相信能在8周后能与读者见面.它详尽细致的讨论了低级库curses,窗口,panel库,menu库,form库,TAM变换库等的使用和注意事项,并给出了可用的实例.由于全文庞大复杂,所以写得慢了些.(慢工出细活?)敬请见谅.此外,由于本人的经验所限,本人所讨论的所有东西有可能是过时的,如果你也是为金融,邮电,证券等只用字符终端的行业开发应用的话,你就找对了.与此相反,如果你是新潮一族的话,请将这些难啃的东西DEL掉.呵呵....
推荐阅读
  • 本文介绍了Linux系统中正则表达式的基础知识,包括正则表达式的简介、字符分类、普通字符和元字符的区别,以及在学习过程中需要注意的事项。同时提醒读者要注意正则表达式与通配符的区别,并给出了使用正则表达式时的一些建议。本文适合初学者了解Linux系统中的正则表达式,并提供了学习的参考资料。 ... [详细]
  • 本文介绍了使用CentOS7.0 U盘刻录工具进行安装的详细步骤,包括使用USBWriter工具刻录ISO文件到USB驱动器、格式化USB磁盘、设置启动顺序等。通过本文的指导,用户可以轻松地使用U盘安装CentOS7.0操作系统。 ... [详细]
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • Webmin远程命令执行漏洞复现及防护方法
    本文介绍了Webmin远程命令执行漏洞CVE-2019-15107的漏洞详情和复现方法,同时提供了防护方法。漏洞存在于Webmin的找回密码页面中,攻击者无需权限即可注入命令并执行任意系统命令。文章还提供了相关参考链接和搭建靶场的步骤。此外,还指出了参考链接中的数据包不准确的问题,并解释了漏洞触发的条件。最后,给出了防护方法以避免受到该漏洞的攻击。 ... [详细]
  • Linux磁盘的分区、格式化的观察和操作步骤
    本文介绍了如何观察Linux磁盘的分区状态,使用lsblk命令列出系统上的所有磁盘列表,并解释了列表中各个字段的含义。同时,还介绍了使用parted命令列出磁盘的分区表类型和分区信息的方法。在进行磁盘分区操作时,根据分区表类型选择使用fdisk或gdisk命令,并提供了具体的分区步骤。通过本文,读者可以了解到Linux磁盘分区和格式化的基本知识和操作步骤。 ... [详细]
  • Ubuntu 9.04中安装谷歌Chromium浏览器及使用体验[图文]
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • PDF内容编辑的两种小方法,你知道怎么操作吗?
    本文介绍了两种PDF内容编辑的方法:迅捷PDF编辑器和Adobe Acrobat DC。使用迅捷PDF编辑器,用户可以通过选择需要更改的文字内容并设置字体形式、大小和颜色来编辑PDF文件。而使用Adobe Acrobat DC,则可以通过在软件中点击编辑来编辑PDF文件。PDF文件的编辑可以帮助办公人员进行文件内容的修改和定制。 ... [详细]
  • 本文详细介绍了Vim编辑器中的三种模式(命令模式、末行模式和编辑模式)以及它们之间的操作区别和切换方法。Vim编辑器凭借其多种命令快捷键和高效率的操作方式,得到了广大厂商和用户的认可。对于想要高效操作文本的用户来说,了解这些模式的使用方法是必不可少的。 ... [详细]
  • 本文介绍了一种处理AJAX操作授权过期的全局方式,以解决Asp.net MVC中Session过期异常的问题。同时还介绍了基于WebImage的图片上传工具类。详细内容请参考链接:https://www.cnblogs.com/starluck/p/8284949.html ... [详细]
  • 本文介绍了一个免费的asp.net控件,该控件具备数据显示、录入、更新、删除等功能。它比datagrid更易用、更实用,同时具备多种功能,例如属性设置、数据排序、字段类型格式化显示、密码字段支持、图像字段上传和生成缩略图等。此外,它还提供了数据验证、日期选择器、数字选择器等功能,以及防止注入攻击、非本页提交和自动分页技术等安全性和性能优化功能。最后,该控件还支持字段值合计和数据导出功能。总之,该控件功能强大且免费,适用于asp.net开发。 ... [详细]
  • 如何实现JDK版本的切换功能,解决开发环境冲突问题
    本文介绍了在开发过程中遇到JDK版本冲突的情况,以及如何通过修改环境变量实现JDK版本的切换功能,解决开发环境冲突的问题。通过合理的切换环境,可以更好地进行项目开发。同时,提醒读者注意不仅限于1.7和1.8版本的转换,还要适应不同项目和个人开发习惯的需求。 ... [详细]
author-avatar
mylvfamily
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有