vs:有关某变量已经在???.obj中定义的错误的解决以前在qq空间发过这么一篇文章:我是这么说的: 该问题应该很多菜鸟和高手都会遇到。虽然我已精通c,但是仍时不时受制于编译器,有些错误的确是疏忽或者没休息好,太着急写代码导致的。而有些则是编译器和语法与生俱来的问题了,前2天还遇到了类模板实现和定义分离的问题折麽。语法这种东西,我认为是由于技术限制无法解决的逻辑矛盾和分析矛盾,因此我认为他们最终给都可以被智能的编译器消除,语法就是人造的,半逻辑的东西,纯粹追求语法无意义,编译器更新总是更好的,想起来最开始的编译器给的限制真是多,比如很早的时候printf不能自己处理16位32位整数,书上还给出了“正确”做法,不过现在编译器早不会有这种bug了。
回归正题,今天编程时遇到了某变量已经在???.obj中定义的错误(都可以说是bug了,好恶心),这个错误原因编译器已经说得很明确,就是重复包含变量的定义了,该变量在某头文件里声明和定义,被多个cpp包含,就会出问题,1个cpp倒是好解决的。看遍网上说法,经典的做法是不在h文件定义全局变量,或者把h文件内容移到cpp,这个有点绝,因为我的工程里的2个cpp就是需要重复使用头文件,放出来岂不是定义2次,太麻烦不喜欢用,因此我开始自己探索如果破除编译器的限制,摸索出能编译通过的方法,纠正编译器的坏毛病!(说白了还是不够智能)。这期间,我试过#pragma once #ifdef#endif 这些我都知道怎么用,不过解决不了问题,网上的回答水平还是比较初级的,自己摸索吧。网上有人说这是个初级问题,初学者才犯,不过也没提出什么高雅的解决方法,是不是高手还是要看会不会解决问题的,问题谁都会碰到,看到有很多所谓高手遇到这种问题不也是只能用下下等方法解决。最终摸索出来如下方法(过程就不说了),且摸索出原理是:编译器在头文件遇到变量定义声明时,会直接连接到obj中,此时你在同一个工程的不同cpp里多次包含同一个头文件,编译器就会说重复定义了这个变量,通俗点说法就是这些cpp共同分享了这个变量;而遇到类型定义,比如定义一个类,那么你在各个不同的cpp里都包含多次都是没什么问题的,也就是说类型定义是不在cpp之间共享的。
但是你不要断章取义,在同一个cpp里多次无意的包含了同一个h文件会提示重定义,此问题可以通过#ifdef 解决,而我说的是不同cpp文件各自包含一次h,这样是没问题的。这只是h文件仅含类型定义的时候啊,别搞错了,如果h文件仅含有变量定义声明,那么整个工程只能有一个cpp包含这个h,其他cpp若想使用则只需用extern 引入该变量即可。如果有第二个cpp包含该文件,则编译器会提示某变量已经在x.obj文件中定义了,你会发现x.cpp包含了该h。
首先,作出如下假设:你有一个1.h需要重复包含,其中有类型定义和全局变量,同时有1.cpp 2.cpp .....主函数在哪里不重要,再假设没有头文件重复包含的情况(该情况也没什么,无非在看懂本文后自己多添几行#ifdef了)。为了简单起见,假设1.h文件内容如下:
#include <windows.h>
class my
{
int i;
};
BOOL (WINAPI* closehandle)(HANDLE hObject)=CloseHandle;
int i=0;
上面是一个类my的定义,下面是变量closehandle和i的定义了
此时我们需要把类型和变量分开,始终要记得类型可以重复包含(别断章取义),变量只能包含一次。为此设置2个预编译宏做区分,修改1.h为如下所示:
#include <windows.h>#ifdef _DefineMyStruct//防止类型重复包含
class my
{
int i;
};
#endif
#ifdef _DefineMyVariable//防止变量定义声明重复包含
BOOL (WINAPI* closehandle)(HANDLE hObject)=CloseHandle;
int i=0;
#endif
再次优化:特意将extern声明放到1.h中,cpp只需要包含头文件即可,免去写extern了,代码如下:
1.h代码如下:
#include <windows.h>
class my
{
int j;
};
#ifdef _DefineMyVariable//防止变量定义声明重复包含
#undef _DefineMyVariable
decltype(MessageBox) *MyMessageBox=MessageBox;
int i=0;
#endif
extern int i;
extern decltype(MessageBox) *MyMessageBox;