如果一个工程中有多个C++源文件,怎么确定先编译哪个源文件呢
最近在编程中遇到一个问题,有两个c++源文件(设为a.cpp和b.cpp),都要用到同一个全局变量i,如果在a文件中声明i,则必须在b文件中用extern声明,否则编译出...
最近在编程中遇到一个问题,有两个c++源文件(设为a.cpp和b.cpp),都要用到同一个全局变量i,如果在a文件中声明i,则必须在b文件中用extern声明,否则编译出错,但是如果在b文件中声明i,则无论在a文件中是否用extern声明i,编译都会通过,故小弟有以上问题,如果有多个源文件,那么编译的先后顺序是怎么确定的呢?
代码太长,下面_NB74110所发代码即是 展开
代码太长,下面_NB74110所发代码即是 展开
4个回答
展开全部
授人以鱼,不如授人以渔.建议楼主好好看看<<C++ primer>>这本书,目前有中文第四版,我非常喜欢它,我也是去年十月份开始学习C++的,看完它再看<<effective C++>>和<<more effective C++>> , 尤其是<<effective C++>>,简直是C++的圣经,非看不可...最后到高级了.你还可以看看<<深入探索C++对象模型>>...我全看完了,感觉受益匪浅.
好了,下面开始解答问题:
解答问题之前,复习一下基本概念;
1:C++中的全局变量,在整个程序中只能定义一次,但可以声明多次(不限次数); 在一个地方定义,,然后在其他地方使用时,要先声明一下;
2:什么叫变量定义? 比如 int i; 这就是定义;
而 extern int i; 则 只是声明;
但如果写作 extern int i = 0; 则这也是定义,不是声明;(是不是有点绕??熟悉了就很简单了)
所以,我觉得你的问题.实际上是源自你对C++语法中变量的定义和声明这两个概念的模糊;
你说你在a.cpp 中声明 i, 而在b.cpp中必须用extern 声明才可通过编译,这是正常的..因为你的i是在a.cpp中定义的..
你说你在b.cpp中声明i, a.cpp中是否使用extern都可以通过编译,这个问题嘛.我估计你的代码实际上仍然是在a.cpp中定义了i,而b.cpp中定义的i不是全局的.
至于你说如果有多个源文件.那么编译顺序如何确定.这个问题很难回答你,恐怕不同的编译器对此的处理都不大相同..我觉得你不应该考虑这个问题..实际上编译器会把不同的源文件分别、单独地编译成独立的模块,最后再链接成一个可执行程序,因为它们都是独立编译的模块,理论上说.编译顺序是不重要的.
我觉得倒是应该告诉你如何正确地管理和使用全局变量;
首先,建立一个 "global.h"(文件名随你,我这里举个例子而已,记得在头文件里加上头文件保护符哦!如果你告诉我你不知道什么是头文件保护符,我强烈建议你不要再往下看了..立刻去买一本C++primer吧);
在global.h文件中.声明你所需要的所有全局变量,以下是 global.h的内容:
#ifndef GLOBAL_H
#define GLOBAL_H
extern int g_i; // 此处是声明,另外,在全局变量前加一个 g_ 是好习惯.
#endif
然后新建一个 global.cpp文件,包含 global.h文件,接着,定义所有的全局变量,
以下是global.cpp的内容:
#include "global.h"
int g_i = 1982; // 此处是定义!!!
至此,一切搞定,最后,在你需要用到全局变量的cpp文件中包含 global.h吧...比如你的a.cpp和b.cpp; 编译顺利了吧?
/////////////////////////////////////////////
看到楼主的新问题了..我再补充回答一下.
问题1:我的疑问是,如果在my.cpp中定义了theApp,则必须在mfc.cpp中用extern声明theApp,否则编译出错;但是如果在mfc.cpp中定义theApp,则不必在my.cpp中声明,编译也能够通过,这是为什么呢?
我的回答: 这个问题还是声明和定义的问题.我之前说过了.一个变量(比如你的这个theApp),在整个程序中只能定义一次, 然后在需要使用它的地方,要先声明后使用.
因此,看看实际情况:你在my.cpp中定义了theApp,当你在mfc.cpp中要使用它,当然要先声明它咯,而声明变量必须加上extern,不然就变成定义了,那么就会导致你在my.cpp和mfc.cpp中定义同名全局变量两次,自然就无法通过编译.
而如果你在mfc.cpp中定义theApp的话,因为在my.cpp中没有直接用到 theApp.所以,就不需要声明了.这下清楚了吧?呵呵.
还有,补充一个基础知识,,我们通常写 int i; 这样的语句是"定义","定义"实际上就起到了"声明"的作用; 所以,如果你不是定义变量,而是单纯要声明一个外部的全局变量(也就是其他cpp文件里的全局变量)的时候,是肯定要加extern的.
我觉得楼主是对 与要加extern感到诧异.
问题2:
这个程序我运行的结果是只有构造函数的那些输出语句执行了,而析构函数的那些输出语句并没有执行,这又是为什么呢?
这个讲起来有点多.涉及到一个C++程序的启动过程:我简单地说说,
以windows为例,点击一个exe程序后,系统创建一个"进程内核对象",创建4G虚拟内存空间以及其他的一些执行程序需要的资源,然后创建"线程内核对象",启动一个线程(也就是主线程了),这个线程调用一个 C++ startup函数,该函数会初始化 你的程序中的所有全局变量,( 这个时候你就看到你 theApp的那些基类的构造函数的执行,并打印出来),所有全局变量构造好以后,才开始执行你写的main函数.
然后,你的main函数 return了.这时,执行一个C++执行期函数exit(),析构你的所有全局变量(也就是theApp), 但这个时候你的console窗口已经退出了.所以你看不到那些析构函数执行时的打印信息了.呵呵.
另外:我真的非常推荐楼主先好好看看<<C++ primer>>和<<effective C++>>这两本书,不要把<<深入浅出mfc>>当成C++教材来看,虽然这本书很好,并且通过mfc,很好地示范了C++ 继承,虚函数的妙用.但是,<深入浅出mfc>的作者侯捷说的好:勿于浮沙筑高台.. 基础打牢非常关键. 当你把C++的基础知识搞清以后,再看深入浅出 mfc 其实是很简单的..
好了,下面开始解答问题:
解答问题之前,复习一下基本概念;
1:C++中的全局变量,在整个程序中只能定义一次,但可以声明多次(不限次数); 在一个地方定义,,然后在其他地方使用时,要先声明一下;
2:什么叫变量定义? 比如 int i; 这就是定义;
而 extern int i; 则 只是声明;
但如果写作 extern int i = 0; 则这也是定义,不是声明;(是不是有点绕??熟悉了就很简单了)
所以,我觉得你的问题.实际上是源自你对C++语法中变量的定义和声明这两个概念的模糊;
你说你在a.cpp 中声明 i, 而在b.cpp中必须用extern 声明才可通过编译,这是正常的..因为你的i是在a.cpp中定义的..
你说你在b.cpp中声明i, a.cpp中是否使用extern都可以通过编译,这个问题嘛.我估计你的代码实际上仍然是在a.cpp中定义了i,而b.cpp中定义的i不是全局的.
至于你说如果有多个源文件.那么编译顺序如何确定.这个问题很难回答你,恐怕不同的编译器对此的处理都不大相同..我觉得你不应该考虑这个问题..实际上编译器会把不同的源文件分别、单独地编译成独立的模块,最后再链接成一个可执行程序,因为它们都是独立编译的模块,理论上说.编译顺序是不重要的.
我觉得倒是应该告诉你如何正确地管理和使用全局变量;
首先,建立一个 "global.h"(文件名随你,我这里举个例子而已,记得在头文件里加上头文件保护符哦!如果你告诉我你不知道什么是头文件保护符,我强烈建议你不要再往下看了..立刻去买一本C++primer吧);
在global.h文件中.声明你所需要的所有全局变量,以下是 global.h的内容:
#ifndef GLOBAL_H
#define GLOBAL_H
extern int g_i; // 此处是声明,另外,在全局变量前加一个 g_ 是好习惯.
#endif
然后新建一个 global.cpp文件,包含 global.h文件,接着,定义所有的全局变量,
以下是global.cpp的内容:
#include "global.h"
int g_i = 1982; // 此处是定义!!!
至此,一切搞定,最后,在你需要用到全局变量的cpp文件中包含 global.h吧...比如你的a.cpp和b.cpp; 编译顺利了吧?
/////////////////////////////////////////////
看到楼主的新问题了..我再补充回答一下.
问题1:我的疑问是,如果在my.cpp中定义了theApp,则必须在mfc.cpp中用extern声明theApp,否则编译出错;但是如果在mfc.cpp中定义theApp,则不必在my.cpp中声明,编译也能够通过,这是为什么呢?
我的回答: 这个问题还是声明和定义的问题.我之前说过了.一个变量(比如你的这个theApp),在整个程序中只能定义一次, 然后在需要使用它的地方,要先声明后使用.
因此,看看实际情况:你在my.cpp中定义了theApp,当你在mfc.cpp中要使用它,当然要先声明它咯,而声明变量必须加上extern,不然就变成定义了,那么就会导致你在my.cpp和mfc.cpp中定义同名全局变量两次,自然就无法通过编译.
而如果你在mfc.cpp中定义theApp的话,因为在my.cpp中没有直接用到 theApp.所以,就不需要声明了.这下清楚了吧?呵呵.
还有,补充一个基础知识,,我们通常写 int i; 这样的语句是"定义","定义"实际上就起到了"声明"的作用; 所以,如果你不是定义变量,而是单纯要声明一个外部的全局变量(也就是其他cpp文件里的全局变量)的时候,是肯定要加extern的.
我觉得楼主是对 与要加extern感到诧异.
问题2:
这个程序我运行的结果是只有构造函数的那些输出语句执行了,而析构函数的那些输出语句并没有执行,这又是为什么呢?
这个讲起来有点多.涉及到一个C++程序的启动过程:我简单地说说,
以windows为例,点击一个exe程序后,系统创建一个"进程内核对象",创建4G虚拟内存空间以及其他的一些执行程序需要的资源,然后创建"线程内核对象",启动一个线程(也就是主线程了),这个线程调用一个 C++ startup函数,该函数会初始化 你的程序中的所有全局变量,( 这个时候你就看到你 theApp的那些基类的构造函数的执行,并打印出来),所有全局变量构造好以后,才开始执行你写的main函数.
然后,你的main函数 return了.这时,执行一个C++执行期函数exit(),析构你的所有全局变量(也就是theApp), 但这个时候你的console窗口已经退出了.所以你看不到那些析构函数执行时的打印信息了.呵呵.
另外:我真的非常推荐楼主先好好看看<<C++ primer>>和<<effective C++>>这两本书,不要把<<深入浅出mfc>>当成C++教材来看,虽然这本书很好,并且通过mfc,很好地示范了C++ 继承,虚函数的妙用.但是,<深入浅出mfc>的作者侯捷说的好:勿于浮沙筑高台.. 基础打牢非常关键. 当你把C++的基础知识搞清以后,再看深入浅出 mfc 其实是很简单的..
展开全部
先编成 .obj
编译开关 -c
例如在DOS窗打命令:
cl -c *.cpp
然后链接
cl *.obj
(MS VC++ 编译器)
其它编译器类似,先编出所有的 .obj, 再 链接 obj
编译开关 -c
例如在DOS窗打命令:
cl -c *.cpp
然后链接
cl *.obj
(MS VC++ 编译器)
其它编译器类似,先编出所有的 .obj, 再 链接 obj
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
正常情况下不应该有你说的问题,我怀疑是对全局变量的理解有些问题。你能把相关代码贴出来吗?
----------------------
我也正在看此书,你说的情况,那是因为
return theApp.m_pCurrentWinApp;
这句中用到了theApp,所以你不论是extern声明还是直接定义,必须是有的,而另一个.cpp中并没有直接使用到theApp,它是调用了另一个.cpp中定义的函数。至于析构的问题,我也正在想,我还真没有拿上机试验过,VC6下,为啥呢,我正在想。
----------------------
看个小程序:
#include <iostream>
#include <cstdio>
using namespace std;
class A{
public:
A(){cout<<"A::A()"<<endl;printf("printf(A::A)");}
~A(){cout<<"A::~A()"<<endl;printf("printf(A::~A)");}
};
using namespace std;
A a1;
int main(){
A a2;
return 0;
}
你可以//掉a1或a2,再看结果。我想,全局量是在main()开始前构造的,在main()的return后析构的,但是main一旦return,随后的cout<<生效发生在
Press any key to continue后
,但printf还生效。
这是我猜的,大约如此。
----------------------
我也正在看此书,你说的情况,那是因为
return theApp.m_pCurrentWinApp;
这句中用到了theApp,所以你不论是extern声明还是直接定义,必须是有的,而另一个.cpp中并没有直接使用到theApp,它是调用了另一个.cpp中定义的函数。至于析构的问题,我也正在想,我还真没有拿上机试验过,VC6下,为啥呢,我正在想。
----------------------
看个小程序:
#include <iostream>
#include <cstdio>
using namespace std;
class A{
public:
A(){cout<<"A::A()"<<endl;printf("printf(A::A)");}
~A(){cout<<"A::~A()"<<endl;printf("printf(A::~A)");}
};
using namespace std;
A a1;
int main(){
A a2;
return 0;
}
你可以//掉a1或a2,再看结果。我想,全局量是在main()开始前构造的,在main()的return后析构的,但是main一旦return,随后的cout<<生效发生在
Press any key to continue后
,但printf还生效。
这是我猜的,大约如此。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
不好意思,有点笔误,把两个定义写成了声明,定义和声明我还是能够区分的,呵呵,其实这是《深入浅出MFC》中的一个程序,现把代码附上:
重点是两个源文件my.cpp和mfc.cpp
//mfc.h头文件
#include <iostream>
using namespace std;
class CObject
{
public:
CObject(){cout<<"CObject Constructor!"<<endl;}
~CObject(){cout<<"CObject Destructor!"<<endl;}
};
class CCmdTarget:public CObject
{
public:
CCmdTarget(){cout<<"CCmdTarget Constructor!"<<endl;}
~CCmdTarget(){cout<<"CCmdTarget Destructor!"<<endl;}
};
class CWinThread:public CCmdTarget
{
public:
CWinThread(){cout<<"CWinThread Constructor!"<<endl;}
~CWinThread(){cout<<"CWinThread Destructor!"<<endl;}
};
class CWinApp:public CWinThread
{
public:
CWinApp* m_pCurrentWinApp;
CWinApp()
{m_pCurrentWinApp=this;
cout<<"CWinApp Constructor!"<<endl;}
~CWinApp(){cout<<"CWinApp Destructor!"<<endl;}
};
class CWnd:public CWinThread
{
public:
CWnd(){cout<<"CWnd Constructor!"<<endl;}
~CWnd(){cout<<"CWnd Destructor!"<<endl;}
};
class CFrameWnd:public CWnd
{
public:
CFrameWnd(){cout<<"CFrameWnd Constructor!"<<endl;}
~CFrameWnd(){cout<<"CFrameWnd Destructor!"<<endl;}
};
class CView:public CWnd
{
public:
CView(){cout<<"CView Constructor!"<<endl;}
~CView(){cout<<"CView Destructor!"<<endl;}
};
CWinApp* AfxGetApp();
//my.h文件
#include "mfc.h"
class CMyWinApp:public CWinApp
{
public:
CMyWinApp(){cout<<"CMyWinApp Constructor!"<<endl;}
~CMyWinApp(){cout<<"CMyWinApp Destructor!"<<endl;}
};
class CMyFrameWnd:public CFrameWnd
{
public:
CMyFrameWnd(){cout<<"CMyFrameWnd Constructor!"<<endl;}
~CMyFrameWnd(){cout<<"CMyFrameWnd Destructor!"<<endl;}
};
//mfc.cpp文件
#include "my.h"
extern CMyWinApp theApp;
CWinApp* AfxGetApp()
{
return theApp.m_pCurrentWinApp;
}
//my.cpp文件
#include "my.h"
CMyWinApp theApp;
int main()
{
CWinApp* pApp=AfxGetApp();
return 0;
}
以上是正确的代码,我的疑问是,如果在my.cpp中定义了theApp,则必须在mfc.cpp中用extern声明theApp,否则编译出错;但是如果在mfc.cpp中定义theApp,则不必在my.cpp中声明,编译也能够通过,这是为什么呢?
另外,这个程序我运行的结果是只有构造函数的那些输出语句执行了,而析构函数的那些输出语句并没有执行,这又是为什么呢?
重点是两个源文件my.cpp和mfc.cpp
//mfc.h头文件
#include <iostream>
using namespace std;
class CObject
{
public:
CObject(){cout<<"CObject Constructor!"<<endl;}
~CObject(){cout<<"CObject Destructor!"<<endl;}
};
class CCmdTarget:public CObject
{
public:
CCmdTarget(){cout<<"CCmdTarget Constructor!"<<endl;}
~CCmdTarget(){cout<<"CCmdTarget Destructor!"<<endl;}
};
class CWinThread:public CCmdTarget
{
public:
CWinThread(){cout<<"CWinThread Constructor!"<<endl;}
~CWinThread(){cout<<"CWinThread Destructor!"<<endl;}
};
class CWinApp:public CWinThread
{
public:
CWinApp* m_pCurrentWinApp;
CWinApp()
{m_pCurrentWinApp=this;
cout<<"CWinApp Constructor!"<<endl;}
~CWinApp(){cout<<"CWinApp Destructor!"<<endl;}
};
class CWnd:public CWinThread
{
public:
CWnd(){cout<<"CWnd Constructor!"<<endl;}
~CWnd(){cout<<"CWnd Destructor!"<<endl;}
};
class CFrameWnd:public CWnd
{
public:
CFrameWnd(){cout<<"CFrameWnd Constructor!"<<endl;}
~CFrameWnd(){cout<<"CFrameWnd Destructor!"<<endl;}
};
class CView:public CWnd
{
public:
CView(){cout<<"CView Constructor!"<<endl;}
~CView(){cout<<"CView Destructor!"<<endl;}
};
CWinApp* AfxGetApp();
//my.h文件
#include "mfc.h"
class CMyWinApp:public CWinApp
{
public:
CMyWinApp(){cout<<"CMyWinApp Constructor!"<<endl;}
~CMyWinApp(){cout<<"CMyWinApp Destructor!"<<endl;}
};
class CMyFrameWnd:public CFrameWnd
{
public:
CMyFrameWnd(){cout<<"CMyFrameWnd Constructor!"<<endl;}
~CMyFrameWnd(){cout<<"CMyFrameWnd Destructor!"<<endl;}
};
//mfc.cpp文件
#include "my.h"
extern CMyWinApp theApp;
CWinApp* AfxGetApp()
{
return theApp.m_pCurrentWinApp;
}
//my.cpp文件
#include "my.h"
CMyWinApp theApp;
int main()
{
CWinApp* pApp=AfxGetApp();
return 0;
}
以上是正确的代码,我的疑问是,如果在my.cpp中定义了theApp,则必须在mfc.cpp中用extern声明theApp,否则编译出错;但是如果在mfc.cpp中定义theApp,则不必在my.cpp中声明,编译也能够通过,这是为什么呢?
另外,这个程序我运行的结果是只有构造函数的那些输出语句执行了,而析构函数的那些输出语句并没有执行,这又是为什么呢?
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询