注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

C语言文件编译链接的过程小问题2--头文件声明的问题  

2011-06-17 14:26:31|  分类: 基本知识 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

头文件声明的问题

今天项目组里有人问一个小问题,改正好后,我觉得有必要深入的理解一下C和C++中头文件中包含变量及数据结构的问题。函数的说明我们已经在前面的博文里“C语言文件编译链接的过程小问题1--extern结构体和函数”说明了,这里不再赘述。
这里强调一下,无论在C还是在C++里,变量都只能定义一次,而可以声明N次,不受限制,但为了美观,大家还是尽量不要没事儿重复声明。机器在这方面是很聪明的,你不用没事儿老告诉他,你是老大。
我们为了编程的便于管理,经常把一些需要定义的常量或经常用的宏集中到一个头文件里,这样,大家在使用的时候儿就可以直接包含它,而不用自己再到处定义一个类似的东东。头文件一般包含类的定义、枚举的定义、extern变量的声明、函数的声明、const int的定义、inline函数的定义。使用或者定义这些实体的文件要包含适当的头文件。
但这里我们要注意的是,头文件是用于声明而不是用于定义的,一定要分清二者的区别,特别是全局变量的定义一定不能在头文件里诸如:
XXXX.h
int len = 0;int width;(只要没有extern ,就是定义) //ERROR
extern int len; //OK
extern int len = 0;//error

正确的方法见上面OK的那种,我们在C文件里,经常是将常量定义成为宏,宏在编译期间只是进行简单的替换,所以不会出现这种问题,但宏会带来一些其它问题,比如不能跟踪错误,无法定位,不知道确切的数据类型等等。

这里我不讲这些,因为有这些不太好的东西,所以我们在PC上编程推荐使用CONST关键字来替代宏定义常量。但一定要注意,在C和C++里这里有一个问题。原来还真没引起过重视,C++里可以在头文件中定义const类型的变量,在C里头文件里即使使用CONST关键字,仍然会引起编译器一个重复定义的错误,在C++的编译器里,由于已经在CONST关键字定义的数据时行了局部化,也就是说将此类型的数据在会在所有包含他的文件里都有一个副本,相当于static const,(但这样一来,肯定开销会大些,)今天这个问题就出现在了这儿,对全局变量的使用也门儿清,对const变量使用也门儿清,对头文件使用使用清楚,但对在头文件里定义二者就不门儿清了,所以产生了疑惑,经过上网查询和查看C++ primer才发现这个区别,再经过用同事的电脑验证,才真正的算是确认了这个区别的存在,还是那句话“纸上学来终觉浅,绝知此事要躬行”。
话又说回来,我们在上面提到的文章里说过结构体的定义的问题,这就又引出来一个问题,为什么它可以?
对于头文件不应该含有定义这一规则,有三个例外:类定义、枚举的定义、值在编译时就已知的const对象(仅C++)、inline函数。这些实体可以在多个源文件中定义,只要每个源文件中的定义是相同的。如果const变量不是用常量表达式初始化的,那么它就不应该在头文件中定义。它应该和其他的变量一样,应该定义在一个源文件中并初始化,在头文件中为它添加extern声明,以便被多个文件共享。但我们应该知道的是,这样做不会引起编译错误,只是一种不好的编程风格,他会造成你的开销比较大,原因正如上面据说,常量类型会在每个包含的文件里形成一个副本。也就是说:const对象(变量)默认是定义该变量的文件的局部变量,连接类型为内连接。所以,当多个源文件include包含同一个含有const对象定义的头文件时,不会产生多重定义的链接错误。这是因为,实质上每个包含该头文件的源文件都有了自己的const变量,都为它分配的存储空间,其名称和值都一样。同时,因为const变量默认连接类型是内连接,所以不会产生多重定义的链接错误。

看另外一种需要引起警惕的方式 :
一般常量定义并无问题,但是,如果 const 要限定的是指针就须特别注意。这里以字符数组为例来说明。
// const_header.h  
#ifndef CONST_HEADER_H_   
#define CONST_HEADER_H_   
 
const char* CONST_STRING = "wangqi";        // 错误!指针 CONST_STRING 并非 const 常量,所以该头文件  
                                            //      被多个文件包含时,会有变量重复定义的编译错误。  
 
const char* const CONST_STRING = "wangqi";  // 正确,CONST_STRING 是指向常量的常量指针。  
const char CONST_STRING[] = "wangqi";       // 正确,CONST_STRING 是 const char [7] 类型。   
char* const CONST_STRING = "wangqi";        // 正确,CONST_STRING 是常量指针。  
#define CONST_STRING "wangqi";              // 正确,传统用法。  
 
static char CONST_STRING[] = "wangqi";      // 正确  
static char* CONST_STRING = "wangqi";   
static const char* CONST_STRING = "wangqi"; // 正确  
 
namespace // 正确  
{  
    char CONST_STRING[] = "wangqi";   
}  
 
namespace // 正确  
{  
    char* CONST_STRING = "wangqi";   
}  
 
namespace // 正确  
{  
    const char* CONST_STRING = "wangqi";   
}  
 
#endif // CONST_HEADER_H_ 
其实这个如果CONST学精的话就不会出现这个问题。  附:用 const 限定符比 #define 好的理由。
    1. const 常量能明确指定类型;
    2. 可以使用 C++ 的作用域规则将定义限制在特定的函数或文件中;
    3. 可以将 const 用于更复杂的类型,如数组和结构。
这段是从网上找的。

  评论这张
 
阅读(1059)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017