编写安全代码:不要在头文件中定义变量

作者:gfree.wind@gmail.com
博客:blog.focus-linux.net   linuxfocus.blog.chinaunix.net
 
微博:weibo.com/glinuxer
QQ技术群:4367710
 
本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。

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

今天这个主题很简单。但是这么一个初级问题,居然真正发生在我的周围。


前几天帮助同事检查一个问题。他这样描述该现象:他定义了一个全局变量,然后调用一个函数F修改了该全局变量,但是退出函数时该全局变量的值又被改了。我到他的调试环境中,先查看了一下现象。问题重现了。—— 我一直认为,所有能够重现的问题都不是问题。只要能够重现,就一定可以修正。


对于这一问题,我的第一反应是竞争引起的。于是我首先使用GDB的set scheduler-locking on,保证其它线程处于停止状态,避免竞争。又试了一次,问题还是存在。在函数退出的时候,打印了一下当时的值。然后退出,再次打印,发现其值变为了初始值。感觉确实有点奇怪。于是看了看他的代码,一看该全局变量定义在头文件中static int g_variable = 0。看到这里,尽管我不知道其它代码是怎么写的。我就想到了问题的原因。这里的全局变量g_variable肯定有两份。函数F和调用者一定在不同的文件中,它们都include了这个头文件。结果在函数F中修改了一个g_variable,而调用者中使用和查看的是另一个g_variable。解决方法是,去一个c文件中定义这个全局变量,然后到头文件中声明。


虽然我很快的解决了这个问题。但是我却想,这个问题真的是一个很初级的问题。而我这位同事已经是一名senior的开发人员了。为什么还会犯这种错误呢?这里我对事不对人。主要的原因还是对于编程的基础没有理解。头文件中不要定义全局变量,看似是一条死的规则。其实只要真正领会什么是头文件,头文件是如何include到.c源文件中的。这条规则根本不需要记忆,而是一种理解。这样会自然的就会写出正确的代码,而不会犯这样的错误。


说到这里,简单说一下头文件的知识。头文件的作用,主要是用于声明变量,函数等等,然后可以被多个源文件引用。其实我认为其根本目的,一是为了代码的整齐,更重要是为了消除重复的代码。因为多个源文件都要相同的声明,这时就可以用一行include 头文件来解决。而include,在预编译阶段,实际上是将头文件中所有的代码都插入到include的位置。真正理解了这个过程,肯定不会犯本文中的这个错误。

头文件:

//
//  comment.h

#ifndef comment_h
#define comment_h

static int ss = 100;

extern int F();

#endif


F()函数所在文件


//
//  comment.c
//

#include <stdio.h>
#include "comment.h"

int F()
{
    ss = 88;
    printf("%s ss = %d \n",__FUNCTION__,ss);
    return ss;
}

main.c 所在文件:

//
//  main.c
//  

#include <stdlib.h>
#include <stdio.h>
#include "comment.h"


int main()
{
    printf("[0]--->[%d]\n",ss);
    F();
    printf("[1]--->[%d]\n",ss);

    return 0;
}

输出结果:

[0]--->[100]
F ss = 88 
[1]--->[100]



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值