[gelöst:] LNK 2001 Error nach "Umzug" von Variablen von .cpp nach Header - mittlerweile OffTopic (DirectX Frag



  • Hallo allerseits!

    Ein paar Variablen, die bisher global in einem namespace lagen, möchte ich jetzt zu Membervariablen machen.

    Allerdings bekomme ich dabei immer wieder LNK2201 Error, woran könnte das liegen und wie kann ich es vermeiden?

    Vorher (funktionierte alles):

    //C3DFenster.cpp:
    #include "C3DFenster.h"
    
    namespace ns_3dfenster 
    {
    ...
     	LPDIRECT3D9             g_pD3D       = NULL; // Used to create the D3DDevice
     	LPDIRECT3DDEVICE9       g_pD3DDevice = NULL; // Our rendering device
     	LPDIRECT3DVERTEXBUFFER9 g_pVB        = NULL; // Buffer to hold vertices
     	LPDIRECT3DVERTEXBUFFER9 g_pVBar[2000]; // Bufferarray to hold vertices 
    ...}
    using namespace ns_3dfenster;
    ....
    

    nachher:

    //C3DFenster.h
    class C3DFenster
    {
    ....
    private:
    	static LPDIRECT3D9             mps_pD3D; //       = NULL; // Used to create the D3DDevice
    	static LPDIRECT3DDEVICE9       mps_pD3DDevice; // = NULL; // Our rendering device
    	static LPDIRECT3DVERTEXBUFFER9 mps_pVB; //        = NULL; // Buffer to hold vertices
    	static LPDIRECT3DVERTEXBUFFER9 mps_pVBar[2000]; // Bufferarray to hold vertices 
    };
    

    führt zu:

    C3DFenster.obj : error LNK2001: unresolved external symbol "private: static struct IDirect3D9 * C3DFenster::mps_pD3D" (?mps_pD3D@C3DFenster@@0PAUIDirect3D9@@A)
    C3DFenster.obj : error LNK2001: unresolved external symbol "private: static struct IDirect3DDevice9 * C3DFenster::mps_pD3DDevice" (?mps_pD3DDevice@C3DFenster@@0PAUIDirect3DDevice9@@A)
    C3DFenster.obj : error LNK2001: unresolved external symbol "private: static struct IDirect3DVertexBuffer9 * C3DFenster::mps_pVB" (?mps_pVB@C3DFenster@@0PAUIDirect3DVertexBuffer9@@A)
    C3DFenster.obj : error LNK2001: unresolved external symbol "private: static struct IDirect3DVertexBuffer9 * * C3DFenster::mps_pVBar" (?mps_pVBar@C3DFenster@@0PAPAUIDirect3DVertexBuffer9@@A)
    Strukturen.exe : fatal error LNK1120: 4 unresolved externals

    Wie man sieht, habe ich ich die Variablen auch schon umbenannt (was mir früher bei manchen LNK Error nützlich war...), aber das brachte hier nichts.
    Außerdem habe ich auch alle "Release" und "Debug" Verzeichnisse und somit alle *.obj Dateien gelöscht.

    Hat jemand noch eine Idee, woran das also liegen könnte?

    Danke und Gruß,
    Dong



  • Solltest du mit MS Visual studion arbeiten, kann ich dir schon mal sagen, dass manche LNK fehler ab und zu aus dem nichts auftauchen, dann: "Bereinigen", und "alles Neucompilieren", dann sindie weg... Mich hats !_so_! n klumpen von nervenzellen gekostet, das glaubtma garnich 😃 ^^

    hier ists aber nicht der fall, da müssen deine statischen variablen nochma ausserhalb der klasse deklariert-definiert werden, also in etwa so:

    class C3DFenster{
    
    //deine statischen vars
    
    };
    
    //immer noch im header, aber ausserhalb der klassendeklaration:
    
    LPDIRECT3D9 C3DFenster::g_pD3D=NULL;
    

    wenndu deine statischen variablen draussen noma deklariert hast, müssn die fehler weg sein

    mfg andrey



  • Ausserdem.... khe khe... hat zwar nix mehr direkt mit c++ zu tun, aber... meine fresse... 2000 VertexBuffer ???? Wozu brauchste denn SOOOO VIEEELE? Hast du bei ebay grad ein NASA supercomputer ersteigert? 😃 verkaufen die vielleicht noch welche? Ich will auch einen haben!!!
    Nur so zur info: alle modelle sollten eigentlich mehr oder weniger in einen vertexbuffer geladen werden, dann kannst du mit dem indexbuffer nur auf das teil zugreifen, das du grade brauchst... kein programm braucht 2000 vertex buffer, ich schwör's 😃 ^^



  • Danke, das klappte aber nicht... 😞

    Andrey schrieb:

    wenndu deine statischen variablen draussen noma deklariert hast, müssn die fehler weg sein

    Ich machte also:

    //C3DFenster.h
    class C3DFenster
    {
    ....
    private:
    	static LPDIRECT3D9             mps_pD3D; //       = NULL; // Used to create the D3DDevice
    	static LPDIRECT3DDEVICE9       mps_pD3DDevice; // = NULL; // Our rendering device
    	static LPDIRECT3DVERTEXBUFFER9 mps_pVB; //        = NULL; // Buffer to hold vertices
    	static LPDIRECT3DVERTEXBUFFER9 mps_pVBar[2000]; // Bufferarray to hold vertices (gemessen)
    
    };
    
    LPDIRECT3D9 C3DFenster::mps_pD3D = NULL;
    LPDIRECT3DDEVICE9 C3DFenster::mps_pD3DDevice = NULL;
    LPDIRECT3DVERTEXBUFFER9 C3DFenster::mps_pVB = NULL;
    

    (das Array brauchte früher ja auch keine Initialisierung, daher ließ ich das hier weg...)
    und die LNK 2001 Errors verwandelten sich in LNK 2005 Errors:

    stdafx.obj : error LNK2005: "private: static struct IDirect3D9 * C3DFenster::mps_pD3D" (?mps_pD3D@C3DFenster@@0PAUIDirect3D9@@A) already defined in C3DFenster.obj
    stdafx.obj : error LNK2005: "private: static struct IDirect3DVertexBuffer9 * C3DFenster::mps_pVB" (?mps_pVB@C3DFenster@@0PAUIDirect3DVertexBuffer9@@A) already defined in C3DFenster.obj
    stdafx.obj : error LNK2005: "private: static struct IDirect3DDevice9 * C3DFenster::mps_pD3DDevice" (?mps_pD3DDevice@C3DFenster@@0PAUIDirect3DDevice9@@A) already defined in C3DFenster.obj
    C3DFenster.obj : error LNK2001: unresolved external symbol "private: static struct IDirect3DVertexBuffer9 * * C3DFenster::mps_pVBar" (?mps_pVBar@C3DFenster@@0PAPAUIDirect3DVertexBuffer9@@A)

    umbennenen (bracht mir manchmal was bei LNK 2005...) brachte auch keine Besserung. 😞

    Und zum Bufferarray:
    Das, was ich darstellen will, paßt nicht in einen Buffer, das weiß ich bereits.
    Und die 2000 sind reiner Vorrrat: Werden die nicht benötigt, brauchen die auch quasi keinen Speicher. Das Programm braucht jedenfalls eine vernünftige Speichermenge.

    Gruß,
    Dong

    P.S.:
    Ach ja: Clean und rebuild brachten auch nichts...



  • Ich habe gerade Testweise eine neue Klasse (mit gleichen Variablen und Funktionen) angelegt, dort verschwinden die LNK2001 Error tatsächlich mit der definition außerhalb der Klasse, und es entstehen auch keine neuen LNK2005 Error.

    An sich war Dein Tipp wohl also richtig, das Problem ist vielleich eher eine verkorkste Klasse....

    Danke,
    Dong



  • dong schrieb:

    Ich habe gerade Testweise eine neue Klasse (mit gleichen Variablen und Funktionen) angelegt, dort verschwinden die LNK2001 Error tatsächlich mit der definition außerhalb der Klasse, und es entstehen auch keine neuen LNK2005 Error.

    ...allerdings nur solange, wie diese Klasse nicht benutzt wird.
    Wird sie dann benutzt, dass gibt es wieder diese LNK2005 Error... 😞



  • Die Definitionen gehören auch in eine Implementierungsdatei, wenn die im Header stehen sind sie in jeder Compilierungs-Einheit, die den Header inkludiert vorhanden.



  • LordJaxom schrieb:

    Die Definitionen gehören auch in eine Implementierungsdatei, wenn die im Header stehen sind sie in jeder Compilierungs-Einheit, die den Header inkludiert vorhanden.

    Ah ja! (Ich dachte, #pragma once) würde mehrfache Header-Einbindung verhindern.

    Aber stimmt tatsächlich:
    Mit der Definition in der .cpp Datei statt im Header ist das wunderbar. 🙂 Danke!
    (Kam mir bisher komisch vor, da so "nackt" außerhalb von Funktionen oder so eine Definition hinzuschreiben....)

    Nur ein Problem habe ich noch:
    Wie definiere ich das Array? Ne for Schleife funktionierte jedenfalls nicht (Syntax Error: for, das darf wohl echt nicht so nackt stehen)....

    Gruß,
    Dong



  • dong schrieb:

    Nur ein Problem habe ich noch:
    Wie definiere ich das Array? Ne for Schleife funktionierte jedenfalls nicht ...

    Ich hab's, so:
    LPDIRECT3DVERTEXBUFFER9 C3DFenster::mprivatestat_pVBar[2000] = {0};

    Gruß,
    Dong



  • Solche konstruktionen um das ganze code in jedem header erspart dir immer die mehrfachdeklarationen und mehrfachdefinitionen:

    #ifndef C3DFENSTER_HPP
    #define C3DFENSTER_HPP
    
    //dein code
    
    #endif
    

    das klappt 100% immer. ich bau das sicherheitshalber bereits in jede datei ein, schaden kann's nicht...

    Jetzt ma ne ganz andere geschichte...
    zu den 2000 vertex buffern...

    IDirect3DVertexBuffer9 Objekte sind schnittstellen, die von IDirect3D9 erzeugt werden. Die werden gebraucht, um vertex-daten direkt im RAM der grafikkarte zu speichern, weil von dort der zugriff viel schneller erfolgen kann. Beim sperren eines vertexbuffers bekommst du ein Array zu verfügung, in den du deine vertices reinkopieren kannst. Die länge dieses arrays kannst du vorher angeben: ob du da hundert oder tausend vertices reinkopieren willst, ist egal, du brauchst nur eine einzige IDirect3DVertexBuffer9 schnittstelle.

    Ausser natürlich, du willst da mehr als 2^32 Vertices reinkopieren, weil dann der IndexBuffer nicht mehr "hochauflösend" genug ist.
    dann hättest du aber ein echtes hardcoreproblem... 2^32 sind 4294967296 vertices, für jedes brauchst du sagen wir mal 28Byte, dann brauchst du schon für einen einzigen vertexbuffer 2^32*28byte=114688 MByte, multipliziert mit 2000 sind es 224000 GB! 😮

    Und das kommt mir ein klitzekleines bisschen verdächtig vor^^ (*rofl*)

    Also jetzt mal raus mit der sprache: WO HAST DU EINE GRAFIKKARTE MIT 250000 GB RAM AUFGETRIEBEN????? 😃 😃 😃 😃 😃 😃 😃 😃



  • Andrey schrieb:

    Solche konstruktionen um das ganze code in jedem header erspart dir immer die mehrfachdeklarationen und mehrfachdefinitionen:

    Falsch, die schützen genausowenig wie #pragma once for Mehrfachdefinitionen in mehreren Objektdateien.



  • warum klappts dann in meinen programmen?
    Obwohl... hm... seltsam... muss ich noch nachschauen, evtl möglich, dass es dann doch nichts bringt 🙄



  • Versteh mich nicht falsch. Include-Guards (alternativ #pragma once) sind wichtig, um beim compilieren einer Datei rekursive und/oder mehrfache Includes derselben Datei zu vermeiden. Über mehrere Compilierungseinheiten hinweg bringen sie allerdings relativ wenig 😉



  • dong schrieb:

    LordJaxom schrieb:

    Die Definitionen gehören auch in eine Implementierungsdatei, wenn die im Header stehen sind sie in jeder Compilierungs-Einheit, die den Header inkludiert vorhanden.

    Ah ja! (Ich dachte, #pragma once) würde mehrfache Header-Einbindung verhindern.

    "#pragma once" verhindert (genau wie Andrey's Konstruktion) nur davor, den Header mehrfach in EINER Übersetzungseinheit einzubinden. Der Linker sieht davon überhaupt nichts mehr (genau genommen sieht noch nicht einmal der Compiler etwas von diesen Konstruktionen, da die vom Präprozessor verarbeitet werden).



  • @LordJaxom & CStoll:

    Danke, ich habe es glaube ich hoffentlich verstanden... 🙂

    Dazu:

    Andrey schrieb:

    Jetzt ma ne ganz andere geschichte...
    zu den 2000 vertex buffern...

    IDirect3DVertexBuffer9 Objekte sind schnittstellen, die von IDirect3D9 erzeugt werden. Die werden gebraucht, um vertex-daten direkt im RAM der grafikkarte zu speichern, weil von dort der zugriff viel schneller erfolgen kann. Beim sperren eines vertexbuffers bekommst du ein Array zu verfügung, in den du deine vertices reinkopieren kannst. Die länge dieses arrays kannst du vorher angeben: ob du da hundert oder tausend vertices reinkopieren willst, ist egal, du brauchst nur eine einzige IDirect3DVertexBuffer9 schnittstelle.

    Ausser natürlich, du willst da mehr als 2^32 Vertices reinkopieren, weil dann der IndexBuffer nicht mehr "hochauflösend" genug ist.
    dann hättest du aber ein echtes hardcoreproblem... 2^32 sind 4294967296 vertices, für jedes brauchst du sagen wir mal 28Byte, dann brauchst du schon für einen einzigen vertexbuffer 2^32*28byte=114688 MByte, multipliziert mit 2000 sind es 224000 GB! 😮

    Und das kommt mir ein klitzekleines bisschen verdächtig vor^^ (*rofl*)

    Also jetzt mal raus mit der sprache: WO HAST DU EINE GRAFIKKARTE MIT 250000 GB RAM AUFGETRIEBEN????? 😃 😃 😃 😃 😃 😃 😃 😃

    Ich hatte anfnags tatsächlich Probleme mit nur einem Puffer, siehe in diesem Thread. Dort wurde mir auch dazu geraten, mehrere Puffer anzulegen.

    Erscheint wohl wirklich etwas oversized, aber ich wählte diese große Größe aus praktischen Gründen:
    Ein ganzes Koordinatengittersystem paßt nicht in einen Puffer, die Zuordnung zu Puffern soll möglichst systematisch sein
    --> Ein Puffer für jede Zeile.

    Genaugenommen so:

    HRESULT C3DFenster::fuellePuffer()
    {
    	CUSTOMVERTEX groessenmasstab[1]; // wird nur für den sizeof Operator weiter unten benötigt, der mit den Zeigern nicht funktioniert.
    	VOID* pVertices;
    
    	//schreibe aktuelle Position und Zoom in den Zwischenspeicher:
    	g_xstart_buffered = m_xstart;
    	g_ystart_buffered = m_ystart;
    	g_fzoom_buffered = m_fzoom;
    	g_fzskal_buffered = *g_fzskal;
    
    	// Erzeuge den Vertex Puffer, falls noch nicht vorhanden
    	if (b_bereit == false) this->bereiteVariablenVor();
    
    for (int j = 0; j < this->yBloe3D; j++)
    {
    	punkte[0].x =  xOffset; 
    	punkte[0].y =  yStep * j + yOffset + yStep;
    	punkte[0].z =  zskal(m_fwert[xpos(0)][ypos(j)]); 
    	punkte[0].color = farbeSand(m_fwert[xpos(0)][ypos(j)]);
    	for (int i = 0; i < this->xBloe3D; i++)
        {
    		punkte[2* i + 1].x =  xStep * i + xOffset; 
    		punkte[2* i + 1].y =  yStep * j + yOffset; 
    		punkte[2* i + 1].z =  zskal(m_fwert[xpos(i)][ypos(j)]); 
    		punkte[2* i + 1].color = farbeSand(m_fwert[xpos(i)][ypos(j)]);
    		punkte[2* i + 2].x =  xStep * i + xOffset + xStep; 
    		punkte[2* i + 2].y =  yStep * j + yOffset + yStep;
    		punkte[2* i + 2].z =  zskal(m_fwert[xpos(i+1)][ypos(j+1)]); 
    		punkte[2* i + 2].color = farbeSand(m_fwert[xpos(i+1)][ypos(j+1)]);
       }
    	punkte[2* this->xBloe3D + 1].x =  xStep * (this->xBloe3D - 1) + xOffset + xStep; 
    	punkte[2* this->xBloe3D + 1].y =  yStep * j + yOffset; 
    	punkte[2* this->xBloe3D + 1].z =  zskal(m_fwert[xpos(this->xBloe3D)][ypos(j)]); 
    	punkte[2* this->xBloe3D + 1].color = farbeSand(m_fwert[xpos(this->xBloe3D)][ypos(j)]);
    
    	// Fill the vertex buffer # j
        if( FAILED( g_pVBar[j]->Lock( 0, (2* this->xBloe3D + 2) * sizeof(groessenmasstab), (void**)&pVertices, 0 ) ) )
            return E_FAIL;
        memcpy( pVertices, punkte, (2* this->xBloe3D + 2) * sizeof(groessenmasstab) );
        g_pVBar[j]->Unlock();
    }
    
    	return S_OK;
    }
    

    mit

    HRESULT C3DFenster::bereiteVariablenVor(void)
    {
    	b_bereit = true; // An dieser Stelle, da ja noch etwas schiefgehen kann.
    	//MessageBox(NULL,L"Puffererzeugung",NULL,NULL);
    
    	//Anlegen der Variablen für die Punktmenge:
    	punkte = new CUSTOMVERTEX[(2* this->xBloe3D + 2)];
    
    	//Erzeugen der Graphikpuffer:
    	for (int j = 0; j < this->yBloe3D; j++)
    	{
    		// Create the vertex buffer # j
    		if( FAILED( g_pd3dDevice->CreateVertexBuffer( (2* this->xBloe3D + 2) *sizeof(CUSTOMVERTEX),
    				                                      0, D3DFVF_CUSTOMVERTEX,
    						                              D3DPOOL_DEFAULT, &g_pVBar[j], NULL ) ) )
    		{
    			b_bereit = false;
    			return E_FAIL;
    		}
    	}
    	return S_OK;
    }
    

    Die Anwendung braucht dabei nie mehr als 16MB RAM, ich denke, das ist akzeptabel.

    Gruß,
    Dong



  • hmmm.... hab ma ganz kurz in den anderen thread reingeschaut, und eigentlich wundert mcih schon, dass in einen buffer nicht mehr als ca. 20000 vertices reinpassen, denn wozu braucht man dann in dem fall 32bit Indexbuffer, mit dem man über 4000000000 vertices adressieren kann? und überhaupt... was zum henker heisst denn jetzt " f'`8k " ???



  • Nichts. TGGC's Tastatur ist einfach nur kaputt.



  • Das bleibt wohl für immer ein geheimnis, für alle ausser TGGC^^ :p



  • Andrey schrieb:

    hmmm.... hab ma ganz kurz in den anderen thread reingeschaut, und eigentlich wundert mcih schon, dass in einen buffer nicht mehr als ca. 20000 vertices reinpassen, denn wozu braucht man dann in dem fall 32bit Indexbuffer, mit dem man über 4000000000 vertices adressieren kann?

    Ja, das mit der Umstellung auf 32bit habe ich auch mal gelesen, allerdings nur für meshes, nicht für vertices.
    Ich weiß aber leider nicht mehr, wo man das einstellen konnte, war glaube ich eine Device Eigenschft.

    Gruß,
    Dong



  • Andrey schrieb:

    was zum henker heisst denn jetzt " f'`8k " ???

    www.games-net.de/hosted/tggc/trash/serious.gif f'`8k

    Gruß, TGGC (\-/ returns)[/quote]


Anmelden zum Antworten