Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Databyte

Alter Hase

  • »Databyte« ist der Autor dieses Themas

Beiträge: 1 040

Wohnort: Na zu Hause

Beruf: Student (KIT)

  • Private Nachricht senden

1

03.07.2009, 11:05

Fehler bei Funktionsaufruf durch Funktionspointer

Hi

Also ich habe mal wieder ein bisl rumexperimentiert und habe
folgenden code zusammengebracht:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>


using namespace std;

template<int I>
struct sizeHolder{ unsigned char p[I]; };


#define array_call(_func, _param)       ( reinterpret_cast<void (_stdcall *)(sizeHolder<sizeof(_param)>)>(_func) )  \
                                            ( *reinterpret_cast<sizeHolder<sizeof(_param)>*>(_param))



void Test(int a, int b, int c)
{
    cout << "a: " << a << "\nb: " << b << "\nc: " << c;
}

int main(int argc, char* argv[])
{
    int p[] = { 5, 4, 99 };
    
    cout << "Size: " << sizeof(p) << "\n";
    array_call(&Test, p);

    cin.get();
    return 0;
} 


array_call ruft eine Funktion auf ohne die Parameter zu wissen,
indem es die parameter auf einen parameter herrunter-castet,
welcher die gleiche größe hat, wie die parameter der funktion zusammen.

wie man sieht, wird die funktion zu einem _stdcall gecastet. Wenn ich das mache,
kriege ich allerdings am ende einen fehler (ja... erst nach dem cin.get() !?):

Quellcode

1
2
3
Run-Time Check Failure #0 - The value of ESP was not properly
saved across a function call.  This is usually a result of calling a function
declared with one calling convention with a function pointer declared with a different calling convention.


Wenn ich das mit _cdecl mache, geht es ;)
Wo liegt also intern der unterschied zwischen _cdecl und _stdcall ?

PS: Wenn ich Test zu nem _stdcall mache, funktioniert es auch mit _stdcall ;)

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

2

03.07.2009, 11:59

Lies mal das hier:
http://de.wikipedia.org/wiki/Aufrufkonvention

Funktioniert das bei dir jetzt auch mit float-Argumenten? Sollte eigentlich dann nicht funktionieren, weil floats anders übergeben werden. Du bewegst dich auf gefährlichem Terrain! Das, was du da machst, ist in jedem Fall undefiniertes Verhalten, und kann je nach Compiler/Plattform völlig unterschiedliche Ergebnisse bringen.

Vermutlich gibt es eine bessere, elegantere Lösung für dein Problem. Also, was genau willst du erreichen?

Databyte

Alter Hase

  • »Databyte« ist der Autor dieses Themas

Beiträge: 1 040

Wohnort: Na zu Hause

Beruf: Student (KIT)

  • Private Nachricht senden

3

03.07.2009, 12:18

Hmm mit float´s funktioniert es auch einwandfrei...

Also ich möcte Funktionsaufrufe in dateien auslagern.
Das bedeutet, dass das programm am anfang mehrere funktionen registriert,
indem ein funktionspointer übergeben wird und halt eine declaration dieser
Funktion in form eines stringes . dann sollen zur laufzeit halt diese funktionen aufgerufen werde.
Luabind macht das zum beispiel. Ich hab mir das schonmal angeguckt aber metaprogrammierung is ziemlich schwer ;)
und boost mag ich irgendwie nicht ;)

Natürlich kann ich auch alle funktionen standatisieren und eine Paramerter-map übergeben...
aber das wollte ich eigentlich nicht ;)

PS: Was ich mich gerade frage: Die parameter werden ja falschherrum auf den stack gelegt... müssten dann nicht die werte in Test(float,float,flaot) umgedreht ankommen ?

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

4

03.07.2009, 13:03

Ich hab's noch nicht verstanden. Kannst du mal ein Beispiel zeigen, wie das nachher aussehen soll?
Eventuell leistet Boost bereits das Gewünschte mit seinen function-Objekten.

Databyte

Alter Hase

  • »Databyte« ist der Autor dieses Themas

Beiträge: 1 040

Wohnort: Na zu Hause

Beruf: Student (KIT)

  • Private Nachricht senden

5

03.07.2009, 14:20

:) ALso ich meine das so:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Als erstes die Funktion

void Say( const std::string& _msg, int times )
{
  for(int i = 0; i < times; ++i)
    sdt::cout << _mgs << std::endl;
}


// Dann den Aufrufer erzeugen

FuncCaller caller;

// Funktion registrieren

caller.RegisterFunction("void Say(string, int)", &Say);

// Und Datei aufrufen

caller.ParseFile("Test.txt");


Dann im Prinzip ein Script:

C-/C++-Quelltext

1
2
3
4
// Test.txt


Say("Hallo", 2)
Say("Bye", 10)


Jetzt wird dann halt Say aufgerufen und die nachricht ausgegeben.
Und bei string wandelt er halt in std::string um

6

03.07.2009, 15:08

naja, du könntest dich auf eine aufrufkonvention festlegen, dann die Stackbelegung in nem Speicherbereich aufbauen, und mit inline-assembler in den richtigen Stack transferieren, sowei die entsprechenden register setzen usw. und die Fuktion von Hand aufrufen.
Probleme:
1. du musst entsprechend gut inline-Assembler können
2. das ist alles andere als Platform unabhängig
3. wenn innerhalb deines Assemblerblock ein Fehler auftaucht, ist der stack im Eimer - und ich hab keinen Schimemr wie das mit exceptions aussieht

7

03.07.2009, 15:31

Also ich habe die Erfahrung gemacht das quasi für alles, wovon es von boost eine Lösung gibt, boost auch die bevorzugte Wahl ist. Da ist einfach alles so genial und einfach und universell und kaum fehleranfällig.
das mit Assembler und soo ist wirklich keine gute Idee. Es ist gut möglich, dass man, wenn man die Code in 10 Jahren nochmal auspackt, überall Probleme und Abstürze bekommt. Mit C++ kann man ja nun wunderbar highlevel programmieren, und wenn du nicht einen enorm guten Grund hast, würde ich dir an dieser Stelle auch dazu raten.
Lieber dumm fragen, als dumm bleiben!

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

8

03.07.2009, 15:39

Du könntest für deine Funktionen jeweils Proxys schreiben, die alle nur einen einzigen Parameter erwarten. Das wäre dann eine Datenstruktur, welche die eigentlichen Parameter z.B. über boost::any kapselt. Diese Proxys packen die Parameter dann aus und übergeben sie an die jeweilige "echte" Funktion.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
// echte Funktion

void myFunction(int a, float b, std::string c)
{
    // tu was

    // ...

}

// Proxy-Funktion

void myFunction_proxy(const Params& p)
{
    // Parameter entpacken und weiterleiten

    myFunction(p.pop<int>(), p.pop<float>(), p.pop<std::string>());
}


Bedeutet natürlich einen gewissen Mehraufwand. Aber ich bin mir sicher, dass man das Generieren der Proxy-Funktion mittels Makro mit einer einzigen Zeile auslösen könnte. Gleichzeitig könnte die Funktion dann direkt bei deinem "Script" registriert werden.

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

9

03.07.2009, 17:30

Hier habe ich mal eine andere kleine Lösung gebastelt:

http://pastebin.com/f3b94f571

Die funktioniert jetzt nur für genau 3 Parameter. Man kann das also einfach nochmal für 2, 1, 0 Parameter machen (oder auch für mehr).

Databyte

Alter Hase

  • »Databyte« ist der Autor dieses Themas

Beiträge: 1 040

Wohnort: Na zu Hause

Beruf: Student (KIT)

  • Private Nachricht senden

10

03.07.2009, 17:51

Hier ist das was ich vorhin mit Meta-programmierung angesprochen habe:

http://www.gamedev.net/reference/program…ort/default.asp

Hmm das finde ich nicht schlecht aber ich bin gerade nicht gewillt mir
boost runterzuladen ;) naja komme ich wohl nicht drumm herrum... ;)
oder ich mach das selber... naja hehe

EDIT: naja das is auch nicht das beste... ich glaub ich mache das mit den defines ;) (also das was david angesprochen hatte )

Werbeanzeige