声明函数可以在没有正文的情况下调用

时间:2010-02-24 05:31:13

标签: c++ visual-studio visual-studio-2008

你能调用一个没有正文的函数但是在代码的标题中声明了吗?请阅读下面的情况。

我正在学习c ++,所以如果我的术语没有,那么你就知道为什么了。如何,我正在读这本名为“高级2D游戏开发”的书,所以如果有人读过这本书,那么也许他们可以帮助我。在c ++中,他在Advanced2D.h中设置了4个外部函数

extern bool game_preload();
extern bool game_init(HWND);
extern void game_update();
extern void game_end();

后来,他在课堂上几次打电话给他们,但从未给他们一个身体。他最终尝试使用所有代码将其编译成lib文件,以便其他项目可以包含它并实际使用这4种方法。

他希望我转到解决方案属性/常规/输出目录,并在发布和调试配置中添加它

$(ProjectDir)..\lib\Advance2D.lib // It didn't work. Still added the libs at default location

仅在上述其他项目中使用上述方法。这就是声明性方法得到它们的时候。

#include <iostream>
#include "..\Engine\Advanced2D.h"
bool game_preload()
{
     //display engine version in a message box
     g_engine->message(g_engine->getVersionText(), "TEST ENGINE");
     //return fail to terminate the engine
     return false;
}

bool game_init(HWND hwnd) { return 0;}
void game_update() {}
void game_end() {}

现在唯一的问题是我收到链接器错误

1>winmain.obj : error LNK2019: unresolved external symbol "bool __cdecl game_preload(void)" (?game_preload@@YA_NXZ) referenced in function _WinMain@16
1>c:\Engine\msvc8\Advance2D\Advance2D\..\lib\Advance2D.lib\Advance2D.exe : fatal error LNK1120: 1 unresolved externals

如果我没有注释掉第一个项目中使用的那些方法,那么项目永远不会被编译?

这家伙坚持认为我在编译时不应该收到任何链接器错误。我引用以下内容

  

假设您输入了代码   没有任何指定的文件   错误,你应该能够   编译引擎项目。那里   应该没有依赖关系   引擎,因为编译器假定   你将提供所需的库   在链接时(当你创建一个   使用引擎的lib执行可执行文件。   这是一个相当复杂的问题   我们将在下一次再次检查   我们增强了几个章节   引擎与新模块和   功能。你不应该看到任何   链接器错误,只有编译器错误   你在打字时弄错了   在代码中。

以下是advanced2D header

// Advanced2D Engine
// Main header file
#ifndef _ADVANCED2D_H
#define _ADVANCED2D_H 1
#include <iostream>
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <dxerr.h>
#include "Timer.h"
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define REVISION 0

#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib, "winmm.lib")

//external variables and functions
extern bool gameover;
extern bool game_preload();
extern bool game_init(HWND);
extern void game_update();
extern void game_end();

namespace Advanced2D
{
    class Engine {
        private:
            int p_versionMajor, p_versionMinor, p_revision;
            HWND p_windowHandle;
            LPDIRECT3D9 p_d3d;
            LPDIRECT3DDEVICE9 p_device;
            LPDIRECT3DSURFACE9 p_backbuffer;
            LPD3DXSPRITE p_sprite_handler;
            std::string p_apptitle;
            bool p_fullscreen;
            int p_screenwidth;
            int p_screenheight;
            int p_colordepth;
            bool p_pauseMode;
            D3DCOLOR p_ambientColor;
            bool p_maximizeProcessor;
            Timer p_coreTimer;
            long p_frameCount_core;
            long p_frameRate_core;
            Timer p_realTimer;
            long p_frameCount_real;
            long p_frameRate_real;
        public:
            Engine();
            virtual ~Engine();
            int Init(int width, int height, int colordepth, bool fullscreen);
            void Close();
            void Update();
            void message(std::string message, std::string title = "ADVANCED 2D");
            void fatalerror(std::string message, std::string title = "FATAL ERROR");
            void Shutdown();
            void ClearScene(D3DCOLOR color);
            void SetDefaultMaterial();
            void SetAmbient(D3DCOLOR colorvalue);
            int RenderStart();
            int RenderStop();
            int Release();
            //accessor/mutator functions expose the private variables
            bool isPaused() { return this->p_pauseMode; }
            void setPaused(bool value) { this->p_pauseMode = value; }
            LPDIRECT3DDEVICE9 getDevice() { return this->p_device; }
            LPDIRECT3DSURFACE9 getBackBuffer() { return this->p_backbuffer; }
            LPD3DXSPRITE getSpriteHandler() { return this->p_sprite_handler; }
            void setWindowHandle(HWND hwnd) { this->p_windowHandle = hwnd; }
            HWND getWindowHandle() { return this->p_windowHandle; }
            std::string getAppTitle() { return this->p_apptitle; }
            void setAppTitle(std::string value) { this->p_apptitle = value; }
            int getVersionMajor() { return this->p_versionMajor; }
            int getVersionMinor() { return this->p_versionMinor; }
            int getRevision() { return this->p_revision; }
            std::string getVersionText();
            long getFrameRate_core() { return this->p_frameRate_core; };
            long getFrameRate_real() { return this->p_frameRate_real; };
            int getScreenWidth() { return this->p_screenwidth; }
            void setScreenWidth(int value) { this->p_screenwidth = value; }
            int getScreenHeight() { return this->p_screenheight; }
            void setScreenHeight(int value) { this->p_screenheight = value; }
            int getColorDepth() { return this->p_colordepth; }
            void setColorDepth(int value) { this->p_colordepth = value; }
            bool getFullscreen() { return this->p_fullscreen; }
            void setFullscreen(bool value) { this->p_fullscreen = value; }
            bool getMaximizeProcessor() { return this->p_maximizeProcessor; }
            void setMaximizeProcessor(bool value) { this->p_maximizeProcessor = value;}
    }; //class
}; //namespace
//define the global engine object (visible everywhere!)
extern Advanced2D::Engine *g_engine;
#endif

Advanced2d class

// Advanced2D Engine
// Main source code file
//includes
#include "Advanced2D.h"
#include <cstdlib>
#include <ctime>
#include <string>
#include <sstream>
#include <list>
#include "winmain.h"

namespace Advanced2D
{
    Engine::Engine()
    {
        srand((unsigned int)time(NULL));
        p_maximizeProcessor = false;
        p_frameCount_core = 0;
        p_frameRate_core = 0;
        p_frameCount_real = 0;
        p_frameRate_real = 0;
        p_ambientColor = D3DCOLOR_RGBA(255,255,255, 0);
        p_windowHandle = 0;
        p_pauseMode = false;
        p_versionMajor = VERSION_MAJOR;
        p_versionMinor = VERSION_MINOR;
        p_revision = REVISION;
        //set default values
        this->setAppTitle("Advanced2D");
        this->setScreenWidth(640);
        this->setScreenHeight(480);
        this->setColorDepth(32);
        this->setFullscreen(false);
        //window handle must be set later on for DirectX!
        this->setWindowHandle(0);
    }

    Engine::~Engine()
    {
        if (this->p_device) this->p_device->Release();
        if (this->p_d3d) this->p_d3d->Release();
    }

    std::string Engine::getVersionText()
    {
        std::ostringstream s;
        s << "Advanced2D Engine v" << p_versionMajor << "." << p_versionMinor
        << "." << p_revision;
        return s.str();
    }

    void Engine::message(std::string message, std::string title)
    {
        MessageBox(0, message.c_str(), title.c_str(), 0);
    }

    void Engine::fatalerror(std::string message, std::string title)
    {
        this->message(message,title);
        Shutdown();
    }

    int Engine::Init(int width, int height, int colordepth, bool fullscreen)
    {
        //initialize Direct3D

        this->p_d3d = Direct3DCreate9(D3D_SDK_VERSION);

        if (this->p_d3d == NULL) {
            return 0;
        }

        //get system desktop color depth
        D3DDISPLAYMODE dm;
        this->p_d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dm);

        //set configuration options for Direct3D
        D3DPRESENT_PARAMETERS d3dpp;
        ZeroMemory(&d3dpp, sizeof(d3dpp));
        d3dpp.Windowed = (!fullscreen);
        d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
        d3dpp.EnableAutoDepthStencil = TRUE;
        d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
        d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
        d3dpp.BackBufferFormat = dm.Format;
        d3dpp.BackBufferCount = 1;
        d3dpp.BackBufferWidth = width;
        d3dpp.BackBufferHeight = height;
        d3dpp.hDeviceWindow = p_windowHandle;

        //create Direct3D device
        this->p_d3d->CreateDevice(
        D3DADAPTER_DEFAULT,
        D3DDEVTYPE_HAL,
        this->p_windowHandle,
        D3DCREATE_HARDWARE_VERTEXPROCESSING,
        &d3dpp,
        &this->p_device);
        if (this->p_device == NULL) return 0;

        //clear the backbuffer to black
        this->ClearScene(D3DCOLOR_XRGB(0,0,0));

        //create pointer to the back buffer
        this->p_device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &this->p_backbuffer);

        //use ambient lighting and z-buffering
        this->p_device->SetRenderState(D3DRS_ZENABLE, TRUE);
        this->p_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
        this->SetAmbient(this->p_ambientColor);

        //initialize 2D renderer
        HRESULT result = D3DXCreateSprite(this->p_device, &this->p_sprite_handler);
        if (result != D3D_OK) return 0;
        //call game initialization extern function
        //if (!game_init(this->getWindowHandle())) return 0;
        //set a default material
        SetDefaultMaterial();
        return 1;
    }


    void Engine::SetDefaultMaterial()
    {
        D3DMATERIAL9 mat;
        memset(&mat, 0, sizeof(mat));
        mat.Diffuse.r = 1.0f;
        mat.Diffuse.g = 1.0f;
        mat.Diffuse.b = 1.0f;
        mat.Diffuse.a = 1.0f;
        p_device->SetMaterial(&mat);
    }

    void Engine::ClearScene(D3DCOLOR color)
    {
        this->p_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
        color, 1.0f, 0);
    }

    void Engine::SetAmbient(D3DCOLOR colorvalue)
    {
        this->p_ambientColor = colorvalue;
        this->p_device->SetRenderState(D3DRS_AMBIENT, this->p_ambientColor);
    }
    int Engine::RenderStart()
    {
        if (!this->p_device) return 0;
        if (this->p_device->BeginScene() != D3D_OK) return 0;
        return 1;
    }
    int Engine::RenderStop()
    {
        if (!this->p_device) return 0;
        if (this->p_device->EndScene() != D3D_OK) return 0;
        if (p_device->Present(NULL, NULL, NULL, NULL) != D3D_OK) return 0;
        return 1;
    }

    void Engine::Shutdown()
    {
        gameover = true;
    }

    void Engine::Update()
    {
        static Timer timedUpdate;
        //calculate core framerate
        p_frameCount_core++;
        if (p_coreTimer.stopwatch(999)) {
        p_frameRate_core = p_frameCount_core;
        p_frameCount_core = 0;
        }
        //fast update with no timing
        game_update();

        //update with 60fps timing
        if (!timedUpdate.stopwatch(14)) {
            if (!this->getMaximizeProcessor())
            {
                Sleep(1);
            }
        }
        else {
            //calculate real framerate
            p_frameCount_real++;

            if (p_realTimer.stopwatch(999)) {
                p_frameRate_real = p_frameCount_real;
                p_frameCount_real = 0;
            }
            //begin rendering
            this->RenderStart();
            //done rendering
            this->RenderStop();
        }
    }
    void Engine::Close()
    {
        game_end();
    }
} //namespace

这是WinMain

#include <sstream>
#include "winmain.h"
#include "Advanced2D.h"
//macro to read the key states
#define KEY_DOWN(vk) ((GetAsyncKeyState(vk) & 0x8000)?1:0)
HINSTANCE g_hInstance;
HWND g_hWnd;
int g_nCmdShow;
//declare global engine object
Advanced2D::Engine *g_engine;
bool gameover;


//window event callback function
LRESULT WINAPI WinProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
    case WM_QUIT:
    case WM_CLOSE:
    case WM_DESTROY:
    gameover = true;
    break;
    }
    return DefWindowProc( hWnd, msg, wParam, lParam );
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int
nCmdShow)
{
    MSG msg;
    srand((unsigned int)time(NULL));
    g_hInstance = hInstance;
    g_nCmdShow = nCmdShow;
    DWORD dwStyle, dwExStyle;
    RECT windowRect;
    /**
    * Create engine object first!
    **/
    g_engine = new Advanced2D::Engine();
    //let main program have a crack at things before window is created
    if (!game_preload()) {
        MessageBox(g_hWnd, "Error in game preload!", "Error", MB_OK);
        return 0;
    }
    //get window caption string from engine
    char title[255];
    sprintf_s(title, "%s", g_engine->getAppTitle().c_str());
    //set window dimensions
    windowRect.left = (long)0;
    windowRect.right = (long)g_engine->getScreenWidth();
    windowRect.top = (long)0;
    windowRect.bottom = (long)g_engine->getScreenHeight();
    //create the window class structure
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX);
    //fill the struct with info
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = (WNDPROC)WinProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = NULL;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = NULL;
    wc.lpszMenuName = NULL;
    wc.lpszClassName = title;
    wc.hIconSm = NULL;
    //set up the window with the class info
    RegisterClassEx(&wc);
    //set up the screen in windowed or fullscreen mode?
    if (g_engine->getFullscreen())
    {
        DEVMODE dm;
        memset(&dm, 0, sizeof(dm));
        dm.dmSize = sizeof(dm);
        dm.dmPelsWidth = g_engine->getScreenWidth();
        dm.dmPelsHeight = g_engine->getScreenHeight();
        dm.dmBitsPerPel = g_engine->getColorDepth();
        dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
        if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
        MessageBox(NULL, "Display mode failed", NULL, MB_OK);
        g_engine->setFullscreen(false);
        }
        dwStyle = WS_POPUP;
        dwExStyle = WS_EX_APPWINDOW;
        ShowCursor(FALSE);
        }
        else {
        dwStyle = WS_OVERLAPPEDWINDOW;
        dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
        }
        //adjust window to true requested size
        AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle);
        //create the program window
        g_hWnd = CreateWindowEx( 0,
        title, //window class
        title, //title bar
        dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
        0, 0, //x,y coordinate
        windowRect.right - windowRect.left, //width of the window
        windowRect.bottom - windowRect.top, //height of the window
        0, //parent window
        0, //menu
        g_hInstance, //application instance
        0); //window parameters
        //was there an error creating the window?
        if (!g_hWnd) {
        MessageBox(g_hWnd, "Error creating program window!", "Error", MB_OK);
        return 0;
    }
    //display the window
    ShowWindow(g_hWnd, g_nCmdShow);
    UpdateWindow(g_hWnd);
    //initialize the engine
    g_engine->setWindowHandle(g_hWnd);
    if (!g_engine->Init(g_engine->getScreenWidth(), g_engine->getScreenHeight(),
    g_engine->getColorDepth(), g_engine->getFullscreen())) {
    MessageBox(g_hWnd, "Error initializing the engine", "Error", MB_OK);
    return 0;
    }
    // main message loop
    gameover = false;
    while (!gameover)
    {
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        g_engine->Update();
    }

    if (g_engine->getFullscreen()) {
        ShowCursor(TRUE);
    }
    g_engine->Close();
    delete g_engine;
    return 1;
}

4 个答案:

答案 0 :(得分:1)

根据您的描述,我想您正在使用某些版本的MS Visual C ++。确保ProjectProperties中有Advance2D.lib - &gt;连接体 - &GT;输入 - &gt;附加依赖项字段。还要在ProjectProperties中添加此库的路径 - &gt;连接体 - &GT;一般 - &gt;其他图书馆目录。您无需更改引擎项目的默认输出路径。顺便说一句,如果你是C ++的初学者,在深入研究“高级”之前,最好先阅读The C++ Programming LanguageThinking In C++之类的内容。

答案 1 :(得分:1)

extern关键字指定该函数将在您所在的编译对象外部实现 - 通常通过lib或其他对象实现。如果要在一个cpp文件中声明一个全局作用域中的变量(在任何函数体之外),则只能在另一个cpp文件中使用外部{variable declaration}引用它 - 这样编译器就知道不要期望定义函数/变量但知道它存在。

事情的声音在这里发生的事情是你链接的对象实际上并没有被链接 - 它应该是。上面的答案告诉你如何 - 我不够快!从您的问题来看,您似乎有第二个项目的来源,可能需要自己构建它 - 当然,我不知道,但如果.lib不存在那么您将需要。

答案 2 :(得分:1)

您的错误是链接器错误,而不是编译器错误。您的代码编译得很好,但是在所有引用的函数都有一个主体之前,链接器无法生成可执行文件。链接器要么不知道包含函数体的库,要么该库不包含它们。

在第一种情况下,您需要更改项目设置并指定正确的名称和位置,Vijay已经描述过。

在第二种情况下,您应该检查该库的导出符号。如果库被编译为C ++,那么函数的名称可能会因类型安全而被破坏(需要指定为在库中导出以防止这种情况),或者它们可能具有不同的签名,您必须更改外部语句。 VC有一个显示库信息的工具,我认为它叫做dumpbin。

答案 3 :(得分:0)

只是想添加以防你仍然坚持这个问题,或者是否有其他人在使用Advanced 2D Game Dev book时找到了这个帖子并想要一些额外的故障排除。

在第16页,他将介绍引擎的VS设置,确保您不仅将目标扩展名更改为.lib,还要确保将“配置类型”设置为“静态库”(.lib),而不是“动态库”图书馆(.dll)。

如果将配置类型保留为动态库,则会看到外部函数的LNK2019错误,因为VC ++链接器期望这些函数具有定义,以便生成有效的DLL文件。编译静态库时,外部化变量,函数等的实际定义不需要存在,直到最终将所有内容链接到DLL或EXE中(如本书后续项目中所做的那样)。

可能对此主题有帮助的一些链接:

使用extern指定链接:msdn.microsoft.com/en-us + /library/0603949d.aspx

演练:创建和使用静态库:msdn.microsoft.com/en-us + /library/ms235627%28VS.80%29.aspx

Microsoft Visual C ++静态和动态库:http://www.codeproject.com/KB/cpp/libraries1.aspx

希望您发现此信息有用!

*注意:抱歉上面的疯狂msdn链接,显然我不能发布多个链接,直到我有更多的StackOverflow信用。