文件重定义顺便回想下static extern

关于static,还有extern,extern平时确实用的少了点,差点都要忘了都。,。还是就说一下好了。

    对于static,已经很熟了,第一是用来局部变量的修饰,只在开始进行赋值,作用域不变但是生命周期延长,常用计数什么的。第二对于全局变量,没有修饰前,是可以被其他文件获取的,但是如果修饰了static那么是只能在本文件内可见。函数当然也差不多了。 其实最常用的还是类里的static成员用来实现常用的n多功能。

    而extern用的少点,其实就是用来引用其他文件的变量的,在其他文件中声明的全局变量,只需要包含然后再这边声明的时候加个extern就可以了,还有一种是用于在C++中调用C库函数,就需要在C++程序中用extern “C”声明要引用的函数。

   然后就说下重定义的,一般来说我们在头文件里都不会进行各种定义,当然除了一些虚类型的简单定义,只需要用条件编译头就能解决重复包含的问题,但对于编译阶段类型重定义错误这个方法是无法解决的,自己说的不怎么清楚,接一下别人的说说http://blog.csdn.net/ipmux/article/details/17306277

   第一种举个例子如果头文件定义了结构,然后再test.c里包含了包含这个头文件的其他两个文件,预处理(见C编译过程)后,test.c里包含两个struct TEST定义,编译器就会报重定义错误。一个巧妙办法是套用下面头文件模板(俗称头文件卫士):

#ifndef _HDRNAME_H //_HDRNAME_H按头文件的文件名取名,防止同名冲突

#define _HDRNAME_H

…… (content of header file)

#endif

当头文件第一次被包含,_HDRNAME_H还未define,#ifndef条件满足,预处理器进入#ifndef和#endif之间,_HDRNAME_H被正式define,头文件内容也得到处理。当再次被包含,由于_HDRNAME_H已定义,开头的#ifndef不再满足,头文件内容被直接忽略。这样防止因头文件重复包含引起的类型重定义错误。这种做法基本算是C的江湖标准了。

    第二种情况,#ifndef能防止头文件重复包含导致的编译阶段类型重定义错误,却无法防止头文件中的全局变量和函数定义导致的链接阶段实体重定义错误。这其实是另一个问题,错误根源在于test.h里包含变量/函数等占用内存的实体元素,而不仅仅是define/struct/union等虚类型。虽然用#ifndef防止test.h重复包含,但注意test1.c和test2.c中都包含test.h,预处理器会把test.h分别附到两个源文件开头,相当于在test1.c和test2.c中重复定义了str1,str2两个全局变量。编译完开始link时,linker会发现test1.obj和test2.obj中都有str1,str2两个符号,于是报错,这跟C命名冲突是同一情况。

解决办法是在.c文件中定义全局变量,然后建一个包含所有全局变量extern声明的头文件,其他所有使用这些变量的.c文件中都要包含这个头文件。如下:

/*****main.c*****/

#include "test.h"

char str1[] = "char1";

char str2[] = "char2";

void main()

{

test1();

test2();

}

/***** test.h*****/

#ifndef _TEST_H_

#define _TEST_H_

extern char str1[];

extern char str2[];

#endif

/*****test1.c*****/

#include "test.h"

void test1() { printf(str1); }

/*****test2.c*****/

#include "test.h"

void test2() { printf(str2); }

在头文件中定义函数,错误现象和原因类似。因此头文件中可以包含类型定义和实体声明,不应该包含实体定义。另外,有时遗漏typedef也会导致类似重定义问题:

typedef struct{

….

}TEST_S;

如果遗漏struct前的typedef,TEST_S就变成无名结构体变量而不是原来的自定义类型,放在头文件里也会出错。

   还有一种自己也没怎么遇到,也提一下,有时源文件要同时包含两个有同名定义的系统或SDK头文件,如同时包含的两个第三方库的API里有同名的自定义类型,也会导致错误。因为一般不方便修改第三方SDK头文件,为解决冲突,可考虑对其中一个库用wrapper方式封装。也就是程序员自己在一个单独.c文件中封装一套全新API,这套API直接调用封装对象lib里的函数并一一对应。这样原lib对应的.h只在wrapper.c文件里包含,而对外API的新.h文件中就可以去掉和其他系统相冲突的定义。

    最后机器还有一种方法,就是直接定义成一个static函数,那么包到项目里,只有一个头文件也是没有问题的,但是当然还是提倡良好的处理方式~~


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值