如何修复链接源文件时未定义的宏?

Posted

技术标签:

【中文标题】如何修复链接源文件时未定义的宏?【英文标题】:How can I fix a macro not being defined when I link a source file? 【发布时间】:2021-11-05 06:19:15 【问题描述】:

问题

我有一个名为“SythConsole.h”的头文件,我在其中定义了一个预处理器条件语句。

#ifndef UNICODE
    #error Please enable unicode for compiler!
#endif

我在我的主文件中定义了UNICODE 宏,但是当我链接源文件(“SythConsole.cpp”)并编译时。我收到一条错误消息,告诉我 UNICODE 尚未在我的主文件中定义。如何链接源文件对象和主文件对象?

错误:

#error 请为编译器启用 unicode!

发生的另一个错误(参数太少):

C:\Programming\C++\Libraries\windowEngine\main.cpp:45:48: 错误:没有匹配函数调用 'Syth::consoleWindow::ConstructConsole(int, int, int, int, const wchar_t [ 5])' window.ConstructConsole(100,100,8,8,L"Test");

C:\Programming\C++\Libraries\windowEngine\include/SythConsole.h:51:17: 注意:候选:'int Syth::consoleWindow::ConstructConsole(int, int, int, int, std::__cxx11 ::wstring, bool)' int ConstructConsole(int width, int height, int fontW, int fontH, std::wstring t_winName, bool t_CursorVis);

我不知道为什么会出现这个错误,因为t_CursorVis 有一个默认参数。

我尝试过的

我尝试不链接源文件并从主文件编译所有内容,我将#include SythConsole.cpp 放在头文件的底部。此更改的结果允许我进行编译并且没有引发任何错误。

信息和源代码

我的编译命令:

g++ main.cpp src/SythConsole.cpp -o main.exe

我的工作空间:

包括 SythConsole.h 源 SythConsole.cpp main.cpp

main.cpp 源代码:

#define UNICODE
#include "include/SythConsole.h"

int main()

    Syth::consoleWindow window;
    window.ConstructConsole(100,100,8,8,L"Test");
    while (true)
    
        /* code */
    
    

SythConsole.cpp:

#include "../include/SythConsole.h"

//Protected
namespace Syth


    int consoleWindow::MakeError(const wchar_t *msg)
    
        wchar_t buffer[256];  // Buffer for containing the error message 
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, 256, NULL); // Format the Error message from GetLastError()
        SetConsoleActiveScreenBuffer(m_hConsoleOrgi);  // Set the screen buffer to the intial screen buffer so the error can be displayed without any interference from the current buffer
        std::wcout << "Error: " << msg << " " << buffer << std::endl;
        return 0;
    


    // Public
    consoleWindow::consoleWindow() : m_ScreenWidth(80), m_ScreenHeight(30), m_MouseX(0), m_MouseY(0), m_WinName(L"Console"), m_CursorVis(false)
    
        m_hConsoleOrgi = GetStdHandle(STD_OUTPUT_HANDLE);
        m_hConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
        m_hConsoleIn = GetStdHandle(STD_INPUT_HANDLE);
    

    int consoleWindow::ConstructConsole(int width, int height, int fontW, int fontH, std::wstring t_winName = L"Console", bool t_CursorVis = false)
    
        if (m_hConsole == INVALID_HANDLE_VALUE)
            return MakeError(L"INVALID HANDLE");

        m_ScreenWidth = width;
        m_ScreenHeight = height;
        m_WinName = t_winName;
        m_RectWindow = 0, 0, 1, 1;
        SetConsoleWindowInfo(m_hConsole, TRUE, &m_RectWindow);

        COORD xyCoord  (short)m_ScreenWidth, (short)m_ScreenHeight ;

        if (!SetConsoleScreenBufferSize(m_hConsole, xyCoord))
            return MakeError(L"SetConsoleScreenBufferSize");
        
        if (!SetConsoleActiveScreenBuffer(m_hConsole))
            return MakeError(L"SetConsoleActiveScreenBuffer");
        
        CONSOLE_FONT_INFOEX cfi;
        cfi.cbSize = sizeof(cfi);
        cfi.nFont = 0;
        cfi.dwFontSize.X = fontW;
        cfi.dwFontSize.Y = fontH;
        cfi.FontFamily = FF_DONTCARE;
        cfi.FontWeight = FW_NORMAL;
        wcscpy_s(cfi.FaceName, L"Terminal");

        if (!SetCurrentConsoleFontEx(m_hConsole, false,&cfi))
            return MakeError(L"SetCurrentConsoleFontEx");
        
        CONSOLE_SCREEN_BUFFER_INFO csbi;
        // Check if the size given by the programmer is bigger than the screen buffer
        if (!GetConsoleScreenBufferInfo(m_hConsole,&csbi))
            return MakeError(L"GetConsoleScreenBufferInfo");
        
        if (m_ScreenHeight > csbi.dwMaximumWindowSize.Y)
            return MakeError(L"Screen Height is too big");

        if (m_ScreenWidth > csbi.dwMaximumWindowSize.X)
            return MakeError(L"Screen Width is too big");

        short tempWidth = m_ScreenWidth-1;
        short tempHeight = m_ScreenHeight-1;
        m_RectWindow = 0, 0, tempWidth, tempHeight;
        
        // Changes the dimensions of the Window 
        if (!SetConsoleWindowInfo(m_hConsole, TRUE, &m_RectWindow))
            return MakeError(L"SetConsoleWindowInfo");
        
        if (!SetConsoleMode(m_hConsoleIn, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT | ENABLE_EXTENDED_FLAGS))
            return MakeError(L"SetConsoleMode");
        
        wchar_t title[256];
        swprintf(title,256,m_WinName.c_str());
        SetConsoleTitle(title);

        CONSOLE_CURSOR_INFO cci;
        if (!GetConsoleCursorInfo(m_hConsole, &cci))
            return MakeError(L"GetConsoleCursorInfo");
        
        cci.bVisible = t_CursorVis;
        m_CursorVis = t_CursorVis;

        if (!SetConsoleCursorInfo(m_hConsole,&cci))
            return MakeError(L"SetCnsoleCursorInfo");
        
        // Create the screen buffer that stores data to be displayed on screen 
        m_ScreenBuf = new CHAR_INFO[m_ScreenWidth*m_ScreenHeight];
        memset(m_ScreenBuf, 0, sizeof(CHAR_INFO)*m_ScreenHeight*m_ScreenWidth);  // Sets all the unintialized 

        return 1;
    

    int consoleWindow::getWidth() const  return m_ScreenWidth; 
    int consoleWindow::getHeight() const  return m_ScreenHeight; 
    int consoleWindow::getMouseX() const  return m_MouseX; 
    int consoleWindow::getMouseY() const  return m_MouseY; 
    
    void consoleWindow::handleMouseEvent(INPUT_RECORD &t_Record)
    
        switch (t_Record.Event.MouseEvent.dwEventFlags)
        
            case MOUSE_MOVED:
                m_MouseX = t_Record.Event.MouseEvent.dwMousePosition.X;
                m_MouseY = t_Record.Event.MouseEvent.dwMousePosition.Y;
                break;

            default:
                break;
        
    

    void consoleWindow::updateInputEvents()
    
        DWORD numEvents 0;
        GetNumberOfConsoleInputEvents(m_hConsoleIn, &numEvents);

        if (numEvents == 0)
            return;

        INPUT_RECORD recordBuf[128];
        ReadConsoleInput(m_hConsoleIn,recordBuf, numEvents, &numEvents);

        for (DWORD i 0; i < numEvents; i++)
        
            switch (recordBuf[i].EventType)
            
                case MOUSE_EVENT:
                    handleMouseEvent(recordBuf[i]);
                    break;
                
                default:
                    break;
            
        
    

    void consoleWindow::clip(int &t_X, int &t_Y)
    
        if (t_X < 0) t_X = 0;
        if (t_X >= m_ScreenWidth) t_X = m_ScreenWidth;
        
        if (t_Y < 0) t_Y = 0;
        if (t_Y >= m_ScreenHeight) t_Y = m_ScreenHeight;

    

    void consoleWindow::draw(int t_X, int t_Y, short t_Char, short t_Attribute)
    
        if (t_X >= 0 && t_X <= m_ScreenWidth && t_Y >= 0 && t_Y <= m_ScreenHeight)
        
            m_ScreenBuf[m_ScreenWidth * t_Y + t_X].Char.UnicodeChar = t_Char;
            m_ScreenBuf[m_ScreenWidth * t_Y + t_X].Attributes = t_Attribute;
        
    

    void consoleWindow::fill(Syth::coord t_Start, Syth::coord t_End, short t_Char, short t_Attribute)
    
        for (int i t_Start.x; i <= t_End.x; i++)
        
            for (int z t_Start.y; z <= t_End.y; z++)
            
                draw(i,z,t_Char,t_Attribute);
            
        
    

    void consoleWindow::drawString(int t_X, int t_Y, std::wstring t_String, short t_Attribute)
    
        for (int i 0, width t_X; i < t_String.size(); i++, width++)
        
            draw(width,t_Y,t_String.at(i), t_Attribute);
        
    

    void consoleWindow::drawTriangle(coord vertex1, coord vertex2, coord vertex3, short t_Char, short t_Attribute)
    
        drawLine(vertex1, vertex2 ,t_Char, t_Attribute);
        drawLine(vertex2, vertex3, t_Char, t_Attribute);
        drawLine(vertex3, vertex1, t_Char, t_Attribute);
    

     void consoleWindow::drawLine(coord t_p1, coord t_p2, short t_Char, short t_Attribute)
    
        float slope = 0.0f;

        if (t_p1.x != t_p2.x)
            slope = ((float)t_p2.y - (float)t_p1.y) / ((float)t_p2.x - (float)t_p1.x);
        

        if (t_p1.x != t_p2.x && abs(slope) <= 1.0f)
        

            if (t_p1.x > t_p2.x)
                std::swap(t_p1, t_p2);

            float c t_p1.y - slope*t_p1.x;

            for (int i t_p1.x; i < t_p2.x; i++)
            
                int bufferY = slope * i + c;
                draw(i,bufferY, t_Char, t_Attribute);
            
            
        
        else
        
            if (t_p1.y > t_p2.y)
                std::swap(t_p1, t_p2);
            
            float slopeY  ((float)t_p1.x - (float)t_p2.x) / ((float)t_p1.y - (float)t_p2.y);
            float cY t_p1.x - slopeY*t_p1.y;

            for (int i t_p1.y; i < t_p2.y; i++)
            
                int bufferX = slopeY * i + cY;
                draw(bufferX, i, t_Char, t_Attribute);
            
        


    

    void consoleWindow::renderQuad(Syth::coord vertex1,Syth::coord vertex2, Syth::coord vertex3, Syth::coord vertex4, short t_Char, short t_Attribute)
    
        drawLine(vertex1, vertex2, t_Char, t_Attribute);
        drawLine(vertex1, vertex3, t_Char, t_Attribute);
        drawLine(vertex1, vertex4, t_Char, t_Attribute);
        drawLine(vertex2, vertex3, t_Char, t_Attribute);
        drawLine(vertex2, vertex4, t_Char, t_Attribute);
        drawLine(vertex3, vertex4, t_Char, t_Attribute);

    

    void consoleWindow::clear()
    
        memset(m_ScreenBuf, 0, sizeof(CHAR_INFO)*m_ScreenHeight*m_ScreenWidth); 
    

    void consoleWindow::update()
    
        short tempW = m_ScreenWidth;
        short tempH = m_ScreenHeight;
        WriteConsoleOutput(m_hConsole,m_ScreenBuf, tempW, tempH, 0,0, &m_RectWindow);
    


    consoleWindow::~consoleWindow()
    
        delete [] m_ScreenBuf;
    

SythConsole.h 源代码:

#pragma once

#ifndef UNICODE
    #error Please enable unicode for compiler!
#endif

#include <string>
#include <windows.h>
#include <iostream>
#include <cmath>
#include <vector>
#include "SythColour.h"
#include "SythKeyMap.h"
#include "SythUtilities.h"


namespace Syth


    class consoleWindow
    
        protected:
            int m_ScreenWidth;
            int m_ScreenHeight;
            int m_MouseX;
            int m_MouseY;
            std::wstring m_WinName;

            CHAR_INFO *m_ScreenBuf;
            SMALL_RECT m_RectWindow;

            bool m_CursorVis;

            HANDLE m_hConsole;
            HANDLE m_hConsoleIn;
            HANDLE m_hConsoleOrgi;
            

        protected:

            int MakeError(const wchar_t *msg);
            void handleMouseEvent(INPUT_RECORD &t_Record);

        public:

            consoleWindow();
            ~consoleWindow();

        public:

            int ConstructConsole(int width, int height, int fontW, int fontH, std::wstring t_winName, bool t_CursorVis);

            int getWidth() const;
            int getHeight() const;
            int getMouseX() const;
            int getMouseY() const;
            void updateInputEvents();

            void clip(int &t_X, int &t_Y);
            void draw (int t_X, int t_Y, short t_Char, short t_Attribute);
            void fill(coord t_Start, coord t_End, short t_Char, short t_Attribute);
            void drawString(int t_X, int t_Y, std::wstring t_String, short t_Attribute);
            void drawLine(coord t_p1, coord t_p2, short t_Char, short t_Attribute);
            void renderQuad(coord vertex1,coord vertex2, coord vertex3, coord vertex4, short t_Char, short t_Attribute);
            void drawTriangle(coord vertex1, coord vertex2, coord vertex3, short t_Char, short t_Attribute);
            void clear();
            void update();
    ;


【问题讨论】:

UNICODE 符号是您应该在构建系统中定义的符号,所以g++ -DUNICODE ...。毕业到 Makefile 或 CMake 后,您可以在顶层添加自定义定义。 从您的帖子来看,现在是时候升级到可以一次性编译您的项目的 Makefile。 @Botje 是的,我将开始研究 Makefile 和 CMake。 【参考方案1】:

预处理器宏对于每个翻译单元都是本地的。无法在 main.cpp 中进行宏定义以在 SythConsole.cpp 中看到。

如果 SythConsole.h 需要定义 UNICODE,那么您必须在包含标头的所有翻译单元中定义该宏。

如果需要在所有翻译单元中定义宏,则不应在源代码中定义,而应在调用编译器时定义。

如何链接源文件和主文件?

源文件未链接。链接是使用编译翻译单元的结果的目标文件完成的。您使用的编译器命令正确链接已编译的程序。

但链接与涉及宏的问题无关。预处理器宏由预处理器处理,预处理发生在编译之前(或者可以看作是编译的子步骤),而链接发生在编译之后。

【讨论】:

以上是关于如何修复链接源文件时未定义的宏?的主要内容,如果未能解决你的问题,请参考以下文章

链接到 MacOS 上预编译的 QuantLib 二进制文件时未定义的 Boost 符号

与共享库链接时未定义的引用

如何编组从 C 头文件中的宏定义的结构?

如何避免与 Windows 头文件中定义的宏发生名称冲突?

在 Vue.js 2 组件中加载时未定义 Webpack 外部 JS 文件

如何修复调用 Thread.sleep() 时未处理异常的编译错误?