могут ли объявленные функции быть вызваны без тела - PullRequest
1 голос
/ 24 февраля 2010

Можете ли вы вызвать функцию, которая не имеет тела, но объявлена ​​в заголовке вашего кода ??Пожалуйста, прочитайте ниже для моей ситуации.

Я изучаю c ++, так что если моя терминология выключена, то вы знаете, почему.Как бы то ни было, я читаю эту книгу под названием «Advanced 2D Game Development», так что если кто-нибудь прочитал эту книгу, возможно, они могут мне помочь.В c ++ он установил 4 внешних функции в Advanced2D.h

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

Позже он вызывает их несколько раз в классе, но никогда не дает им тела.В конечном итоге он пытается со всем кодом скомпилировать его в файл lib, чтобы другие проекты могли включить его и фактически использовать эти 4 метода.

Он хотел, чтобы я пошел в свойства решений / General / Output Directoryи добавьте это как в Release, так и в Debug Configuration

$(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

// 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 ]

1 голос
/ 24 февраля 2010

Ключевое слово extern указывает, что функция будет реализована в объекте компиляции, внешнем по отношению к тому, в котором вы находитесь - обычно через lib или другой объект. Если бы вы объявили переменную в глобальной области видимости в одном файле cpp (вне любого тела функции), вы можете ссылаться на нее только с помощью внешнего {объявление переменной} в другом файле cpp - так, чтобы компилятор знал, что функция / переменная не будет определена но знаю, что оно существует.

То, что происходит здесь под звуки вещей, заключается в том, что объект, на который вы ссылаетесь, на самом деле не связан - это должно быть. Ответ выше говорит вам, как - я недостаточно быстр! Из вашего вопроса кажется, что у вас есть источник для этого второго проекта, и, возможно, вам, возможно, понадобится создать его самостоятельно - конечно, я не знаю, но если .lib не существует, вам понадобится.

1 голос
/ 24 февраля 2010

Ваша ошибка - ошибка компоновщика, а не ошибка компилятора. Ваш код компилируется нормально, но компоновщик не может сгенерировать исполняемый файл, пока все ссылочные функции не будут иметь тела. Компоновщик либо не знает о библиотеке, которая содержит тела функций, либо эта библиотека не содержит их.

В первом случае вам нужно изменить настройки проекта и указать правильные имена и местоположения, Vijay уже описал это.

Во втором случае вы должны проверить экспортированные символы этой библиотеки. Если библиотека была скомпилирована как C ++, имена функций могли бы быть искажены для обеспечения безопасности типов (для предотвращения этого необходимо указать их экспортированные в библиотеку), или они могли бы иметь другую сигнатуру, и вы должны изменить свои выражения extern. В VC есть инструмент для отображения информации о библиотеках, я думаю, он назывался dumpbin.

1 голос
/ 24 февраля 2010

Из вашего описания, я полагаю, вы используете какую-то версию MS Visual C ++. Убедитесь, что у вас есть Advance2D.lib в поле ProjectProperties -> Linker-> Input -> Additional Dependencies. Также добавьте путь к этой библиотеке в ProjectProperties -> Linker-> General -> Дополнительные каталоги библиотеки. Не требуется, чтобы вы изменили путь вывода по умолчанию для проекта движка. Кстати, если вы новичок в C ++, лучше прочитайте что-то вроде Язык программирования C ++ или Thinking In C ++ , прежде чем углубляться в "продвинутые" вещи.

0 голосов
/ 07 августа 2010

Просто хотел добавить, если вы все еще застряли в этой проблеме, или если кто-то еще найдет эту ветку и захочет решить некоторые дополнительные проблемы при работе с книгой Advanced 2D Game Dev.

На стр.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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...