C++ 为什么包含语句的顺序如此重要?

C++ 为什么包含语句的顺序如此重要?,c++,wxwidgets,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 Record

在我的程序(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
#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)) ===|
我会遇到如下错误:

#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
#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++(或WxWigGET)的行为是这样的吗?< /P> 编辑:

Serial.h的包含

#ifndef SERIAL_H
#define SERIAL_H

#include <windows.h>
//#include <wx/msw/winundef.h>
#include <stdio.h> // necessary for sprintf
#include <string>
\ifndef SERIAL\u H
#定义序列号
#包括
//#包括
#包括//sprintf所必需的
#包括

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

正如评论所指出的,这可能是因为
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>
\ifndef SERIAL\u H
#定义序列号
#包括
#包括
#包括
#包括
//#包括
#包括//sprintf所必需的
#包括
如果要正确执行,您应该在
Serial.h
中找出您实际需要的一个(或多个),但是添加所有这些应该可以清除错误

编译预处理器时,通过将指定文件复制到主文件的
#include
位置,处理
#include
。这是一个递归过程,文件可以
#包含
#包含
文件的文件,等等

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


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

仅需遵循一些常见做法,这可能无法回答您的问题,但会为您指出正确的方向:

  • 始终让您不要在同一个文件中包含相同的头文件,这意味着混淆,但请使用下图理解它:
有效:

-#include "some.h"
-#include "some1.h"
-#include "some.h"
--#include "some1.h"
-#include "some.h"
-#include "some1.h"
--#include "some.h"
有效:

-#include "some.h"
-#include "some1.h"
-#include "some.h"
--#include "some1.h"
-#include "some.h"
-#include "some1.h"
--#include "some.h"
无效:

-#include "some.h"
-#include "some1.h"
-#include "some.h"
--#include "some1.h"
-#include "some.h"
-#include "some1.h"
--#include "some.h"
因此,除非你知道自己在做什么,否则不要筑巢

您的问题的一个可能解决方案是在
Serial.h
中包含
wx\thread.h
wx\dialog.h
wx\string.h
,请尝试一下,然后告诉我

为什么调用
#按顺序包含

因为只有当你理解这样的事情时,这才有意义,阿里需要清洁修理他的车,阿里不知道如何修理他的车,所以阿里会打电话给机械师修理,所以这里我们可以说(阿里依赖机械师)

- #include "mechanic.h"

- #include "Ali.h"

问题在于
根据是否定义了
UNICODE
standard(即Windows下的)宏定义了不同的符号。如果首先包含wxWidgets头,默认情况下采用Unicode构建,那么在包含
之前,它们会为您定义
Unicode
,一切都很好

如果先包含
,则此时未定义
UNICODE
,但当稍后包含wxWidgets头时,它们使用
wxUSE_UNICODE=1
(这也是默认值),从而导致您观察到的编译问题


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

什么是
Serial.h
?当您使用双引号时,它应该意味着它是您项目中的一个文件-如果您自己的头依赖于其他头,那么您编写的
Serial.h
不正确
Serial.h
应负责其自身的包含。可能相关:Show us Serial.h。这意味着一个或多个标题被破坏。顺序在正确编写的代码中并不重要。这意味着
Serial.h
中的某些内容取决于一个或多个
wx
标题中的声明或定义。
Serial.h
需要包含它所依赖的那些头文件,或者您总是需要确保包含“Serial.h”的其他文件只有在包含
wx
头文件之后才这样做。我理解您的意思,但是从这些类中的每一个来看,将这些头包含在
Serial.h
中没有多大意义,因为Serial只是打开并从串行通信读取,是其他人编写的类,而记录部分才是真正需要这些的部分…记录打开串行通信,解析输入并进一步处理。有几种情况下,没有任何意义,但您必须这样做,因为这是唯一的解决方法,请尝试按顺序调用它们,它们在单个文件中相互依赖,可能是主文件或任何头文件,为什么按顺序调用很重要,让我们在回答中讨论这是错误的。如果some1.h需要some.h的名称,那么some1.h应该包含some.h。如果源文件需要来自some.h和some1.h的名称,那么它应该同时包含这两个文件。标记为“无效:”的代码是完全正确的,只要一些.h有适当的include guards。@PeteBecker最好不要把初学者和
guards
东西混淆,最好的做法是尽量不要使用它们,我错了吗?你完全错了。包括警卫是C和C++编程的基本工具。不使用它们会导致神秘的相互依赖、顺序依赖和混乱的错误消息。