程序员法则:程序员要求法则2

、头文件中#ndef
——————————
千万不要忽略了头件#ndef这是个很关键东西比如你有两个C文件这两
个C文件都了同个头文件而编译时这两个C文件要同编译成个可运行文件
于是问题来了大量声明冲突

还是把头文件内容都放在#ndef和#end中吧不管你头文件会不会被多个文件引用
管你头文件会不会被多个文件引用
你都要加上这个般格式是这样:

#ndef <标识>
# <标识>

......
......

#end

<标识>在理论上来说可以是自由命名但每个头文件这个“标识”都应该是唯
标识命名规则般是头文件名全大写前后加下划线并把文件名中“.”也变成下划
线如:stdio.h

#ndef _STDIO_H_
# _STDIO_H_

......

#end

(BTW:预编译有多很有用功能你会用预编译吗?)
(BTW:预编译有多很有用功能你会用预编译吗?)


8、在堆上分配内存
—————————
可能许多人对内存分配上“栈 stack”和“堆 heap”还不是很明白包括些科班出身
人也不明白这两个概念我不想过多说这两个东西简单来讲stack上分配内存
系统自动释放heap上分配内存系统不释放哪怕退出块内存还是在那里
stack般是静态分配内存heap上般是动态分配内存

由malloc系统分配内存就是从堆上分配内存从堆上分配内存定要自己释放
用free释放不然就是术语——“内存泄露”(或是“内存漏洞”)—— Memory Leak
于是系统可分配内存会随malloc越来越少直到系统崩溃还是来看看“栈内存”和
“堆内存”差别吧

栈内存分配
—————
char*
AllocStrFromStack
{
char pstr[100];
pstr;
}


堆内存分配
—————
char*
AllocStrFromHeap( len)
{
char *pstr;

( len <= 0 ) NULL;
( char* ) malloc( len );
}

对于第那块pstr内存在返回时就被系统释放了于是所返回char*什么
也没有而对于第 2个是从堆上分配内存所以哪怕是退出时也不释放
以第 2个返回内存没有问题可以被使用定要free释放不然就是Mem
ory Leak!

在堆上分配内存很容易造成内存泄漏这是C/C最大“克星”如果你要稳定
那么就不要出现Memory Leak所以我还是要在这里千叮咛万嘱付在使用malloc系统
蛑龈叮谑褂胢alloc系统
(包括callocrealloc)时千万要小心

记得有个UNIX上服务应用大约有几百C文件编译而成运行测试良好等使用
每隔 3个月系统就是down搞得许多人焦头烂额查不出问题所在只好每隔
两个月人工手动重启系统出现这种问题就是Memery Leak在做怪了在C/C中这种
问题总是会发生所以你定要小心个Rational检测工作——Pury可以帮你测
试你有没有内存泄漏

我保证做过许多C/C工程都会对malloc或是有些感冒当你什么时候
在使用malloc和种轻度紧张和惶恐感觉时你就具备了这方面修养了

对于malloc和free操作有以下规则:

1) 配对使用个malloc就应该有个free(C中对应为和delete)
2) 尽量在同层上使用不要像上面那种malloc在而free在最好在同
层上使用这两个
3) malloc分配内存定要free后指针定要设置为NULL

注:虽然现在操作系统(如:UNIX和Win2k/NT)都有进程内存跟踪机制也就是如果你
有没有释放内存操作系统会帮你释放但操作系统依然不会释放你中所有产生了M
emory Leak内存所以最好还是你自己来做这个工作(有时候不知不觉就出现Mem
ory Leak了而且在几百万行代码中找无异于海底捞针Rational有个工具叫Pury
蛐械拇胫姓椅抟煊诤5桌陶耄琑ational有个工具叫Pury
可能很好帮你检查Memory Leak)



9、变量
————————
接上变量定要被化再使用C/C编译器在这个方面不会像JAVA样帮你
切都需要你自己来如果你使用了没有变量结果未知员从
来都会在使用变量前化变量如:

1) 对malloc分配内存进行mem清零操作(可以使用calloc分配块全零内存
)
2) 对些栈上分配struct或进行(最好也是清零)

不过话又说回来了化也会造成系统运行时间有开销所以也不要对所有
变量做这个也没有意义员知道哪些变量需要哪些则不需要
如:以下这种情况则不需要

char *pstr; /* 串 */
pstr = ( char* ) malloc( 50 );
( pstr NULL ) exit(0);
strcpy( pstr, "Hello Wrold" );
strcpy( pstr, "Hello Wrold" );

但如果是下面种情况最好进行内存(指针是个危险东西定要
)

char **pstr; /* */
pstr = ( char** ) malloc( 50 );
( pstr NULL ) exit(0);
/* 让指针都指向NULL */
mem( pstr, 0, 50*(char*) );

而对于全局变量和静态变量定要声明时就你不知道它第次会在哪里
被使用所以使用前这些变量是比较不现实定要在声明时就化它们如:

Links *plnk = NULL; /* 对于全局变量plnk化为NULL */





10、h和c文件使用
—————————
—————————
H文件和C文件如何用呢?般来说H文件中是declare(声明)C文件中是(定义
)C文件要编译成库文件(Windows下是.obj/.libUNIX下是.o/.a)如果别人要
使用你那么就要引用你H文件所以H文件中般是变量、宏定义、枚举、结
构和接口声明就像个接口介绍说明文件而C文件则是实现细节

H文件和C文件最大用处就是声明和实现分开这个特性应该是公认但我仍然看到
有些人喜欢把写在H文件中这种习惯很不好(如果是C对于其模板在V
C中只有把实现和声明都写在个文件中VC不支持export关键字)而且如果在H
文件中写上实现你还得在makefile中把头文件依赖关系也加上去这个就会让
makefile很不规范标准

最后个最需要注意地方就是:带全局变量不要放在H文件中!

例如有个处理信息结构:

char* errmsg = {
/* 0 */ "No error",
/* 1 */ "Open file error",
/* 2 */ "Failed in sending/receiving a message",
/* 3 */ "Bad arguments",
/* 4 */ "Memeroy is not enough",
/* 5 */ "Service is down; try later",
/* 6 */ "Unknow information",
/* 7 */ "A operation has failed",
/* 8 */ "Permission denied",
/* 9 */ "Bad configuration file format",
/* 10 */ "Communication time out",
......
......
};
请不要把这个东西放在头文件中如果你这个头文件被5个库(.lib或是.a)所
用到于是他就被链接在这5个.lib或.a中而如果你用到了这5个库中
并且这些都用到了这个出错信息那么这份信息将有5个副本存在于你
行文件中如果你这个errmsg很大而且你用到库更多执行文件
也会变得很大

正确写法应该把它写到C文件中然后在各个需要用到errmsgC文件头上加上 extern
char* errmsg; 外部声明让编译器在链接时才去管他这样就只会有个err
msg存在于执行文件中而且这样做很利于封装

我曾遇到过最疯狂就是在我目标文件中这个errmsg共有112个副本执行文
件有8M左右当我把errmsg放到C文件中并为千多个C文件加上了extern声明后
库文件尺寸都下降了20%左右而我执行文件只有5M了下子少了3M啊

〔 备注 〕
—————
有朋友对我说这个只是个特例如果errmsg在执行文件中存在多个副本时
以加快运行速度理由是errmsg多个复本会让系统内存换页降低达到效率提升
像我们这里所说errmsg只有当某要用errmsg时如果内存隔得比较远
产生换页反而效率不高


生副本导致执行文件尺寸变大不仅增加了系统装载时间也会让在内存中占更
页面而对于errmsg这样数据般来说在系统运行时不会经常用到所以还是产
内存换页也就不算频繁权衡的下还是只有份errmsg效率高即便是像logmsg
这样频繁使用数据操作系统内存调度算法会让这样频繁使用页面常驻于内存
所以也就不会出现内存换页问题了
11、出错信息处理
—————————
你会处理出错信息吗?哦它并不是简单输出看下面举例:

( p NULL ){
prf ( "ERR: The poer is NULL&#92;n" );
}

告别学生时代编程吧这种编程很不利于维护和管理出错信息或是提示信息应该统
处理而不是像上面这样写成个“硬编码”第10条对这方面处理做了部分说
如果要管理信息那就要有以下处理:

/* 声明出错代码 */
# ERR_NO_ERROR 0 /* No error */
# ERR_OPEN_FILE 1 /* Open file error */
# ERR_SEND_MESG 2 /* sending a message error */
# ERR_BAD_ARGS 3 /* Bad arguments */
# ERR_MEM_NONE 4 /* Memeroy is not enough */
# ERR_SERV_DOWN 5 /* Service down try later */
# ERR_UNKNOW_INFO 6 /* Unknow information */
# ERR_SOCKET_ERR 7 /* Socket operation failed */
# ERR_PERMISSION 8 /* Permission denied */
# ERR_BAD_FORMAT 9 /* Bad configuration file */
# ERR_TIME_OUT 10 /* Communication time out */

/* 声明出错信息 */
char* errmsg = {
/* 0 */ "No error",
/* 1 */ "Open file error",
/* 2 */ "Failed in sending/receiving a message",
/* 3 */ "Bad arguments",
/* 4 */ "Memeroy is not enough",
/* 5 */ "Service is down; try later",
/* 6 */ "Unknow information",
/* 7 */ "A operation has failed",
/* 8 */ "Permission denied",
/* 9 */ "Bad configuration file format",
/* 10 */ "Communication time out",
/* 10 */ "Communication time out",
};

/* 声明代码全局变量 */
long errno = 0;

/* 打印出错信息 */
void perror( char* info)
{
( info ){
prf("%s: %s&#92;n", info, errmsg[errno] );
;
}

prf("Error: %s&#92;n", errmsg[errno] );
}

这个基本上是ANSI处理实现细节了于是当你中有时你就可以这样处理:

bool CheckPermission( char* userName )
{
( strcpy(userName, "root") != 0 ){
errno = ERR_PERMISSION_DENIED;
(FALSE);
}

.
Tags:  程序员工作要求 程序员的要求 程序员要求 程序员法则

延伸阅读

最新评论

发表评论