为什么#include语句的顺序如此重要?

时间:2016-11-21 10:07:15

标签: c++ wxwidgets

在我的程序(wxWidgets,code :: blocks)中,我注意到一些我不太了解的行为。如果我像这样写我的标题:

#ifndef RECORDTHREAD_H
#define RECORDTHREAD_H

#include <wx/thread.h>
#include <wx/dialog.h>
#include <wx/string.h>

#include "Serial.h"

class RecordTrackDialog;

class RecordThread : public wxThread
{
    public:
        RecordThread(RecordTrackDialog* parent);
        virtual ~RecordThread();
    protected:
    private:
        virtual ExitCode Entry();

        Serial m_serial;
};

#endif // RECORDTHREAD_H

(使用#include "Serial.h"作为最后一个包含语句)一切正常,但是当我更改这样的include语句时:

#ifndef RECORDTHREAD_H
#define RECORDTHREAD_H

#include "Serial.h"

#include <wx/thread.h>
#include <wx/dialog.h>
#include <wx/string.h>

我得到这样的错误:

||=== Build: Debug in WindowsDgpsGUI (compiler: GNU GCC Compiler) ===|
C:\wxWidgets-3.0.2\include\wx\msw\winundef.h||In function 'HWND__* CreateDialog(HINSTANCE, LPCTSTR, HWND, DLGPROC)':|
C:\wxWidgets-3.0.2\include\wx\msw\winundef.h|38|error: cannot convert 'LPCTSTR {aka const char*}' to 'LPCWSTR {aka const wchar_t*}' for argument '2' to 'HWND__* CreateDialogParamW(HINSTANCE, LPCWSTR, HWND, DLGPROC, LPARAM)'|
C:\wxWidgets-3.0.2\include\wx\msw\winundef.h||In function 'HFONT__* CreateFont(int, int, int, int, int, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, LPCTSTR)':|
C:\wxWidgets-3.0.2\include\wx\msw\winundef.h|69|error: cannot convert 'LPCTSTR {aka const char*}' to 'LPCWSTR {aka const wchar_t*}' for argument '14' to 'HFONT__* CreateFontW(int, int, int, int, int, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, LPCWSTR)'|
C:\wxWidgets-3.0.2\include\wx\msw\winundef.h||In function 'HWND__* CreateWindow(LPCTSTR, LPCTSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, LPVOID)':|
C:\wxWidgets-3.0.2\include\wx\msw\winundef.h|94|error: cannot convert 'LPCTSTR {aka const char*}' to 'LPCWSTR {aka const wchar_t*}' for argument '2' to 'HWND__* CreateWindowExW(DWORD, LPCWSTR, LPCWSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, LPVOID)'|
C:\wxWidgets-3.0.2\include\wx\msw\winundef.h||In function 'HMENU__* LoadMenu(HINSTANCE, LPCTSTR)':|
C:\wxWidgets-3.0.2\include\wx\msw\winundef.h|111|error: cannot convert 'LPCTSTR {aka const char*}' to 'LPCWSTR {aka const wchar_t*}' for argument '2' to 'HMENU__* LoadMenuW(HINSTANCE, LPCWSTR)'|
C:\wxWidgets-3.0.2\include\wx\msw\winundef.h||In function 'HWND__* FindText(LPFINDREPLACE)':|
C:\wxWidgets-3.0.2\include\wx\msw\winundef.h|126|error: cannot convert 'LPFINDREPLACE {aka FINDREPLACEA*}' to 'LPFINDREPLACEW {aka FINDREPLACEW*}' for argument '1' to 'HWND__* FindTextW(LPFINDREPLACEW)'|
C:\wxWidgets-3.0.2\include\wx\msw\winundef.h||In function 'HICON__* LoadIcon(HINSTANCE, LPCTSTR)':|
C:\wxWidgets-3.0.2\include\wx\msw\winundef.h|311|error: cannot convert 'LPCTSTR {aka const char*}' to 'LPCWSTR {aka const wchar_t*}' for argument '2' to 'HICON__* LoadIconW(HINSTANCE, LPCWSTR)'|
C:\wxWidgets-3.0.2\include\wx\msw\winundef.h||In function 'HBITMAP__* LoadBitmap(HINSTANCE, LPCTSTR)':|
C:\wxWidgets-3.0.2\include\wx\msw\winundef.h|324|error: cannot convert 'LPCTSTR {aka const char*}' to 'LPCWSTR {aka const wchar_t*}' for argument '2' to 'HBITMAP__* LoadBitmapW(HINSTANCE, LPCWSTR)'|
||=== Build failed: 7 error(s), 0 warning(s) (0 minute(s), 1 second(s)) ===|

我不太明白这种行为,因为标题是一个线程,错误来自使用该线程的对话框。任何人都可以解释为什么C ++(或wxWidgets)表现得像这样吗?

编辑:

Serial.h的包含

#ifndef SERIAL_H
#define SERIAL_H

#include <windows.h>
//#include <wx/msw/winundef.h>
#include <stdio.h> // necessary for sprintf
#include <string>

这似乎符合Marco的评论,但我不能包含该部分......

3 个答案:

答案 0 :(得分:1)

正如评论所指出的那样,可能是因为Serial.h依赖于3 wx\xxxx个文件中的定义而包含主文件(RecordThread.h?)。

将它们添加到这样的Serial.h,你将获得与以前相同的效果。

#ifndef SERIAL_H
#define SERIAL_H

#include <wx/thread.h>
#include <wx/dialog.h>
#include <wx/string.h>

#include <windows.h>
//#include <wx/msw/winundef.h>
#include <stdio.h> // necessary for sprintf
#include <string>

如果您要正确地执行此操作,您应该在Serial.h中确定您实际需要哪一个(或多个),但添加所有这些应该清除错误。

编译预处理器句柄#include时,就好像指定的文件被复制到#include位置的主文件中一样。这是一个递归过程,文件可以#include文件#include文件等。

似乎有很多关于#include的神秘主义和新手中的预处理器。它实际上只是一个文本处理工具。

在现代C的许多地方,你必须在使用之前声明(引入/定义)符号/标识符。如果在头文件中声明了该符号/标识符,则在使用之前应该#include该文件。

答案 1 :(得分:1)

问题在于<windows.h>定义了不同的符号,具体取决于是否定义了UNICODE标准(在Windows下,即在Windows下)。如果您首先包含wxWidgets标头(默认情况下为Unicode构建),那么在包含UNICODE并且一切正常之前,它们会为您定义<windows.h>

如果您首先包含<windows.h>,则此时未定义UNICODE,但是当您稍后包含wxWidgets标头时,它们会使用wxUSE_UNICODE=1(这也是默认值)导致您正在观察的编译问题。

确保您永远不会遇到此类问题的最简单方法是在项目设置或makefile中全局定义UNICODE

答案 2 :(得分:0)

只是一些常见的做法需要跟进,这可能无法回答您的问题,但指出了正确的方向:

  • 始终让你不要在同一个文件中#include使用相同的头文件,这意味着会让人感到困惑,但请使用以下图表理解它:

<强>有效:

-#include "some.h"
-#include "some1.h"

<强>有效:

-#include "some.h"
--#include "some1.h"

无效:

-#include "some.h"
-#include "some1.h"
--#include "some.h"

除非你知道自己在做什么,否则不要嵌套......

问题的一个可能解决方案是在wx\thread.h中加入wx\dialog.hwx\string.hSerial.h,试一试,然后告诉我

为什么要按顺序调用#include

因为只有了解这样的事情才有意义,阿里需要清理他的车,阿里不知道如何修理他的车,所以阿里会叫机修修理它,所以我们可以说那个(阿里依靠机械师)

- #include "mechanic.h"

- #include "Ali.h"