/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
Callback til C++-funktion fra C-funktion
Fra : Troels Arvin


Dato : 01-10-03 20:45

Hej,

Sidder og prøver at lære OpenGL og programmerer i C++. Den
OpenGL-implementation, jeg benytter, har derimod et C-API. Både OpenGL og
C(++) er nye for mig.

I glut har man funktionen glutDisplayFunc(funktion), hvormed man kan
fortælle OpenGL hvilken funktion man vil have kaldt, når det er tid til
at "display'e":

....
glutDisplayFunc(funktionsnavn)
....

Nu er det sådan, at jeg gerne vil have kaldt en funktion i et C++ objekt
(objektet kalder jeg "t"), men det kan jeg tilsyneladende ikke få lov
til. Fx. virker følgende ikke:

glutDisplayFunc(t.display);
glutDisplayFunc(t.display());

Hvordan får jeg via et C-API fortalt, at jeg vil benytte en C++ callback?

--
Greetings from Troels Arvin, Copenhagen, Denmark


 
 
Bertel Brander (01-10-2003)
Kommentar
Fra : Bertel Brander


Dato : 01-10-03 21:05

Troels Arvin wrote:

> glutDisplayFunc(t.display);
> glutDisplayFunc(t.display());
>
> Hvordan får jeg via et C-API fortalt, at jeg vil benytte en C++ callback?
>

Du kan lave t.display() static, eller lave en C funktion der kalder
t.display(). Du kan ikke få en C funktion til at kalde en normal
C++ funktion i en klasse.

Problemet er at Glut ikke kender dine klasser og ikke kan se hvilket
objekt den skal bruge til at kalde t.display().

Hvilen metode man vil anvende afhænger af om man kun har et globalt
t objekt, eller man har en række t objekter.
I det simple tilfælde har man kun et t objekt, og man kan så lave en
global variabel der peger på dette objekt og lave en C-funktion (som
man giver til glutDisplayFunc()) der kalder display gennem denne
pointer.

/b


Ole Nielsby (02-10-2003)
Kommentar
Fra : Ole Nielsby


Dato : 02-10-03 00:24


Bertel Brander <bertel@post4.tele.dk> skrev:

> Troels Arvin wrote:
>
> > glutDisplayFunc(t.display);
> > glutDisplayFunc(t.display());
> >
> > Hvordan får jeg via et C-API fortalt, at jeg vil benytte en C++
callback?
> >
>
> Du kan lave t.display() static, eller lave en C funktion der kalder
> t.display(). Du kan ikke få en C funktion til at kalde en normal
> C++ funktion i en klasse.
>
> Problemet er at Glut ikke kender dine klasser og ikke kan se hvilket
> objekt den skal bruge til at kalde t.display().
>
> Hvilen metode man vil anvende afhænger af om man kun har et globalt
> t objekt, eller man har en række t objekter.
> I det simple tilfælde har man kun et t objekt, og man kan så lave en
> global variabel der peger på dette objekt og lave en C-funktion (som
> man giver til glutDisplayFunc()) der kalder display gennem denne
> pointer.

Man kan faktisk med lidt snilde og en smule assemblerkode
give en ikke-statisk metode som parameter til API'et via en
thunk - en stump maskinkode som genereres dynamisk i en
memory-blok du selv er ansvarlig for at allokere/deallokere;
lav f.eks. en klasse til formålet.

Thunken skal poppe returadressen, pushe objektpointeren,
pushe returadressen og hoppe til metoden. I NASM-syntaks
ser det sådan ud (- for en virtuel metode), og ud fra den
antagelse at kaldekonventionen er stdcall (der tillader at
registrene eax, ecx og edx overskrives):

mov eax,obj; din thunk-generator indsætter objektet
pop ecx
mov edx,[eax]; vtable
push eax
push ecx
jmp [edx+offset]; din thunk-generator indsætter vtable-offset.

(vtable-offset er 0 for første virtuelle metode, 4 for den næste...)

(.NET-platformen har indkapslet denne teknik i delegates...)

ON/Fjern sneglen fra min svaradresse


Jonas Meyer (02-10-2003)
Kommentar
Fra : Jonas Meyer


Dato : 02-10-03 14:47

"Ole Nielsby" <ole.nielsby@snailmail.dk> wrote in message
news:3f7b61fa$0$54873$edfadb0f@dread11.news.tele.dk...
[snip]
> Man kan faktisk med lidt snilde og en smule assemblerkode
> give en ikke-statisk metode som parameter til API'et via en
> thunk - en stump maskinkode som genereres dynamisk i en
> memory-blok du selv er ansvarlig for at allokere/deallokere;
> lav f.eks. en klasse til formålet.

Jeg kan ikke helt se formålet med det?
Hvis objektet oprettes og nedlægges ved kald, så kan man vel ligeså
godt lave en statisk metode, den kan jo præcis gøre det samme?

Eller jeg misforstår måske det du siger?

[snip, assembler mix]
> (vtable-offset er 0 for første virtuelle metode, 4 for den næste...)

Eh? hvad så hvis metoden ikke er virtual? hvis jeg bruger MI?
Så vidt jeg husker fra mine timer, så er det næppe så simpelt?

Jeg forstår nok ikke helt din løsning, men det virker som om du prøver
at gøre noget smart med assembler kode, som ligeså let kan
klares med en simpel c-funktion?

mvh Jonas




Mogens Hansen (02-10-2003)
Kommentar
Fra : Mogens Hansen


Dato : 02-10-03 16:23



"Jonas Meyer" <someone@microsoft.com> wrote in message
news:<blha33$7nk$1@munin.diku.dk>...

[8<8<8<]
> Eh? hvad så hvis metoden ikke er virtual? hvis jeg bruger MI? Så vidt
> jeg husker fra mine timer, så er det næppe så simpelt?

Der hvor jeg har set teknikken brugt gemmer man kun objekt pegeren sammen
med call-thunken.
Når thunken så bliver kaldt hiver man pegeren ud igen i assembler, og laver
så kaldet i almindelig C++.
På den måde er man ud over problemer med multiple arv, spørgsmål om hvorvidt
funktionen er virtuel og i givet fald hvilket slot i vtable funktionen
bruger. Det håndteres helt almindeligt at compileren, og der er mindre
assembler kode, der er afhængig af compiler-version, compiler optioner etc.

> Jeg forstår nok ikke helt din løsning, men det virker som om du prøver
> at gøre noget smart med assembler kode, som ligeså let kan klares med
> en simpel c-funktion?

Udgangspunktet for den løsning er at opgaven _ikke_ ligeså let kan klares
med en simpel c-funktion.

Venlig hilsen

Mogens Hansen



Jonas Meyer (02-10-2003)
Kommentar
Fra : Jonas Meyer


Dato : 02-10-03 16:54

"Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
news:blhfje$43q$1@news.cybercity.dk...
> Udgangspunktet for den løsning er at opgaven _ikke_ ligeså let kan klares
> med en simpel c-funktion.

Jeg forstår det ikke så.

Hvad er det for et problem vi prøver at løse? Mit gæt er at vi vil have en
funktion kaldt på et objekt, istedet for en c funktion - Men den hersens
thunk hvad er det?
Blot en peger til det objekt? hvornår bliver den lavet og allokeret? og
hvorhenne?

Jonas



Mogens Hansen (02-10-2003)
Kommentar
Fra : Mogens Hansen


Dato : 02-10-03 17:30


"Jonas Meyer" <someone@microsoft.com> wrote in message
news:blhhhi$ee2$1@munin.diku.dk...
> "Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
> news:blhfje$43q$1@news.cybercity.dk...
> > Udgangspunktet for den løsning er at opgaven _ikke_ ligeså let kan
klares
> > med en simpel c-funktion.
>
> Jeg forstår det ikke så.

Ok.

>
> Hvad er det for et problem vi prøver at løse? Mit gæt er at vi vil have en
> funktion kaldt på et objekt, istedet for en c funktion - Men den hersens
> thunk hvad er det?

Et eksempel fra den virkelige verden:

Når man laver en C++ objekt-orienteret wrapper af det C baserede Win32 API,
vil man typisk have en klasse Button (som arver fra Window), som man kan
lave mange objekter af.
Når der bliver klikket på et Button _objekt_ skal der kaldes en
_member_-funktion, således at man nemt kan skelne mellem om det er "Ok"
eller "Cancel", der er trykket på.
Win32 API'et kender ikke noget til Button klassen og de forskellige Button
objekter, og kan derfor ikke kalde nogen member-funktion direkte.
Win32 API'et kan kun kalde en C-funktion (WinProc) med information om
hvilket vindue (HWND) der er trykket på. Et eller andet sked i C++ wrapper
biblioteket skal der ske en konvertering fra HWND til Button objekt.
Dette kan naturligvis gøres med en tabel (std::map<HWND, Button*>), men det
kan gøres hurtigere (konstant, kort tid) med en call-thunk.
Hvis C-callback funktionen ikke på en eller anden måde havde information med
til at skelne mellem objekterne (som man reelt kan med HWND i Win32 API'et)
var der få andre muligheder end at bruge en call-thunk.

Dette kan findes i biblioteker som Borland OWL og Microsoft ATL.

> Blot en peger til det objekt?

Og en lille stump assembler kode.

> hvornår bliver den lavet og allokeret? og
> hvorhenne?

Koden er et datamedlem i Window klassen - helt seriøst
Der ligger f.eks. et char-array, hvor man skriver pointeren til objektet og
nogle fornuftige op-coder (oversat assembler).
Der bliver altså lavet en ny funktion for hvert objekt !

<C++ kode fra et af mine egne biblioteker>
class InstanceThunk
{
public:
InstanceThunk(Window* wnd, WNDPROC wndproc)
{
call = 0xE8u; // CALL rel32
#if defined(__BORLANDC__) && (0x0550 == __BORLANDC__ || 0x0551 ==
__BORLANDC__)
// Borland C++Builder V5.0
offset = offsetof(InstanceThunk, code) - offsetof(InstanceThunk,
proc);
#elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 500) &&
defined(_WIN32)) || defined(__COMO__)
// Intel C++ for Windows V5.0
// Comeau C++ for Windows
// offsetof is not supported by Intel C++
offset = 8; //offsetof(InstanceThunk, code) - offsetof(InstanceThunk,
proc);
#endif
proc = wndproc;
window = wnd;
// POP ECX
//
// Pop return address of call into ecx (address of member "proc")
//
code[0] = 0x59u;

// MOV EDX, [ECX+4]
//
// load "window" into edx
//
code[1] = 0x8B;
code[2] = 0x51u;
code[3] = 0x04u;

// JMP [ECX]
//
// jump to window function provided
code[4] = 0xFFu;
code[5] = 0x21u;
}

WNDPROC WndProc(void)
{
return reinterpret_cast<WNDPROC>(this);
}

private:
unsigned char call;
int offset;
WNDPROC proc;
Window* window;
unsigned char code[6];

private:
InstanceThunk(const InstanceThunk&);
InstanceThunk& operator=(const InstanceThunk&);
};

template <class WND_T>
class CustomWindow : public Window
{
public:
CustomWindow(LPCTSTR lpWindowName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU hMenu, LPVOID lpParam);
~CustomWindow();

// ...
static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
LPARAM lParam);

// ...

private:
InstanceThunk instanceThunk;

private:
CustomWindow(const CustomWindow&);
const CustomWindow& operator=(const CustomWindow&);
};


template <class WND_T>
inline CustomWindow<WND_T>::CustomWindow(LPCTSTR lpWindowName, DWORD
dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU hMenu, LPVOID lpParam) :
Window(WND_T::CreateWindow_(lpWindowName, dwStyle, x, y, nWidth, nHeight,
hWndParent, hMenu, lpParam)),
instanceThunk(this, reinterpret_cast<WNDPROC>(WndProc))
{
::SetWindowLong(*this, GWL_WNDPROC,
reinterpret_cast<DWORD>(instanceThunk.WndProc()));
}




<C++ kode fra et af mine egne biblioteker>

Venlig hilsen

Mogens Hansen



Jonas Meyer (02-10-2003)
Kommentar
Fra : Jonas Meyer


Dato : 02-10-03 18:12

Mogens - Tak for svaret, nu fatter jeg det.

Ganske snedigt.

mvh Jonas



Jesper Matthiesen (04-10-2003)
Kommentar
Fra : Jesper Matthiesen


Dato : 04-10-03 13:57

Hej Hajer
Lige et lille spørgsmål fra en C/C++ novice. Jeg tror der er et eller andet
jeg ikke er med på men her følger et forsøg på at forklare.
Så vidt jeg har forstået af glut-eksemplerne så sendes en funktionpointer
med til glutDisplayFunc. Det sker ved at der i ens c-fil er defineret en
metode, lad os kalde den foo, og i eksemplerne
siger man så glutDisplayFunc(foo) eller noget i den stil. Hvorfor kan man
ikke i dette tilfælde bruge C++'s syntaks til at oprette funktionspointere
og så sende sådan en med. Altså noget med

void (FooClass::*pointer2foo)(void);
pt2Foo = FooClass::foo;

....hvor man så sendte pt2Foo med?

Mvh Jesper


"Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
news:blhjhe$9ov$1@news.cybercity.dk...
>
> "Jonas Meyer" <someone@microsoft.com> wrote in message
> news:blhhhi$ee2$1@munin.diku.dk...
> > "Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
> > news:blhfje$43q$1@news.cybercity.dk...
> > > Udgangspunktet for den løsning er at opgaven _ikke_ ligeså let kan
> klares
> > > med en simpel c-funktion.
> >
> > Jeg forstår det ikke så.
>
> Ok.
>
> >
> > Hvad er det for et problem vi prøver at løse? Mit gæt er at vi vil have
en
> > funktion kaldt på et objekt, istedet for en c funktion - Men den hersens
> > thunk hvad er det?
>
> Et eksempel fra den virkelige verden:
>
> Når man laver en C++ objekt-orienteret wrapper af det C baserede Win32
API,
> vil man typisk have en klasse Button (som arver fra Window), som man kan
> lave mange objekter af.
> Når der bliver klikket på et Button _objekt_ skal der kaldes en
> _member_-funktion, således at man nemt kan skelne mellem om det er "Ok"
> eller "Cancel", der er trykket på.
> Win32 API'et kender ikke noget til Button klassen og de forskellige Button
> objekter, og kan derfor ikke kalde nogen member-funktion direkte.
> Win32 API'et kan kun kalde en C-funktion (WinProc) med information om
> hvilket vindue (HWND) der er trykket på. Et eller andet sked i C++ wrapper
> biblioteket skal der ske en konvertering fra HWND til Button objekt.
> Dette kan naturligvis gøres med en tabel (std::map<HWND, Button*>), men
det
> kan gøres hurtigere (konstant, kort tid) med en call-thunk.
> Hvis C-callback funktionen ikke på en eller anden måde havde information
med
> til at skelne mellem objekterne (som man reelt kan med HWND i Win32
API'et)
> var der få andre muligheder end at bruge en call-thunk.
>
> Dette kan findes i biblioteker som Borland OWL og Microsoft ATL.
>
> > Blot en peger til det objekt?
>
> Og en lille stump assembler kode.
>
> > hvornår bliver den lavet og allokeret? og
> > hvorhenne?
>
> Koden er et datamedlem i Window klassen - helt seriøst
> Der ligger f.eks. et char-array, hvor man skriver pointeren til objektet
og
> nogle fornuftige op-coder (oversat assembler).
> Der bliver altså lavet en ny funktion for hvert objekt !
>
> <C++ kode fra et af mine egne biblioteker>
> class InstanceThunk
> {
> public:
> InstanceThunk(Window* wnd, WNDPROC wndproc)
> {
> call = 0xE8u; // CALL rel32
> #if defined(__BORLANDC__) && (0x0550 == __BORLANDC__ || 0x0551 ==
> __BORLANDC__)
> // Borland C++Builder V5.0
> offset = offsetof(InstanceThunk, code) - offsetof(InstanceThunk,
> proc);
> #elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 500) &&
> defined(_WIN32)) || defined(__COMO__)
> // Intel C++ for Windows V5.0
> // Comeau C++ for Windows
> // offsetof is not supported by Intel C++
> offset = 8; //offsetof(InstanceThunk, code) -
offsetof(InstanceThunk,
> proc);
> #endif
> proc = wndproc;
> window = wnd;
> // POP ECX
> //
> // Pop return address of call into ecx (address of member "proc")
> //
> code[0] = 0x59u;
>
> // MOV EDX, [ECX+4]
> //
> // load "window" into edx
> //
> code[1] = 0x8B;
> code[2] = 0x51u;
> code[3] = 0x04u;
>
> // JMP [ECX]
> //
> // jump to window function provided
> code[4] = 0xFFu;
> code[5] = 0x21u;
> }
>
> WNDPROC WndProc(void)
> {
> return reinterpret_cast<WNDPROC>(this);
> }
>
> private:
> unsigned char call;
> int offset;
> WNDPROC proc;
> Window* window;
> unsigned char code[6];
>
> private:
> InstanceThunk(const InstanceThunk&);
> InstanceThunk& operator=(const InstanceThunk&);
> };
>
> template <class WND_T>
> class CustomWindow : public Window
> {
> public:
> CustomWindow(LPCTSTR lpWindowName, DWORD dwStyle,
> int x, int y, int nWidth, int nHeight,
> HWND hWndParent, HMENU hMenu, LPVOID lpParam);
> ~CustomWindow();
>
> // ...
> static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
> LPARAM lParam);
>
> // ...
>
> private:
> InstanceThunk instanceThunk;
>
> private:
> CustomWindow(const CustomWindow&);
> const CustomWindow& operator=(const CustomWindow&);
> };
>
>
> template <class WND_T>
> inline CustomWindow<WND_T>::CustomWindow(LPCTSTR lpWindowName, DWORD
> dwStyle,
> int x, int y, int nWidth, int nHeight,
> HWND hWndParent, HMENU hMenu, LPVOID lpParam) :
> Window(WND_T::CreateWindow_(lpWindowName, dwStyle, x, y, nWidth,
nHeight,
> hWndParent, hMenu, lpParam)),
> instanceThunk(this, reinterpret_cast<WNDPROC>(WndProc))
> {
> ::SetWindowLong(*this, GWL_WNDPROC,
> reinterpret_cast<DWORD>(instanceThunk.WndProc()));
> }
>
>
>
>
> <C++ kode fra et af mine egne biblioteker>
>
> Venlig hilsen
>
> Mogens Hansen
>
>



Mogens Hansen (04-10-2003)
Kommentar
Fra : Mogens Hansen


Dato : 04-10-03 14:57


"Jesper Matthiesen" <matthiesenjesper_fjern_dette@hotmail.com> wrote in
message news:blmfsf$lvk$1@sunsite.dk...

[8<8<8<]
> Lige et lille spørgsmål fra en C/C++ novice.

Glimrende.
Men lige en advarsel - den omtalte call-thunk teknik er forholdsvis sjældent
brugt og bestemt ikke noget man skal rode sig ud i tidligt.
Teknikken har mange problemer, men kan være nyttig i visse situationer.
Den befinder sig bedst dybt begravet i et bibliotek, som f.eks. Microsoft
ATL, så brugeren af biblioteket end ikke ved at den anvendes.

[8<8<8<]
> Hvorfor kan man
> ikke i dette tilfælde bruge C++'s syntaks til at oprette funktionspointere
> og så sende sådan en med. Altså noget med
>
> void (FooClass::*pointer2foo)(void);
> pt2Foo = FooClass::foo;
>
> ...hvor man så sendte pt2Foo med?

Der skal skelnes mellem static member funktioner og ikke static
memberfuntioner.

For at kalde en static member funktion, behøves der ikke at eksistere noget
objekt.
Man kan således blot skrive:
foo::bar();
for at kalde den.
Der er således ikke nogen forskel på at kalde en static member funktioner og
en global funktion (Bortset fra lidt detaljer omkring scoping og tilgang til
static data member - men glem det indtil videre).

For at kalde en ikke static member funktion, skal man _både_ have et objekt
_og_ en funktion.
Man skal altså skrive noget i retningen af:
class foo
{
public:
void bar();
};

foo f; // lav et objekt
f.bar(); // kald en member funktion

Hvis man så har en pointer til en member funktion, skal man (som du skrev)
skrive noget i retningen af
typedef void (foo::*func_ptr_type)();
func_ptr_type func_ptr = &foo::bar;
men vi mangler forsat et objekt for at kunne bruge den til noget.
Altså:
foo f;
(f.*func_ptr)(); // kald via pointer til member funktion
foo* fp = &f;
(fp->*func_ptr)(); // kald via pointer til member funktion

Det første problem ved at forsøge at give en pointer til member-funktion med
som call-back argument er at den ikke kan bruges til noget uden et objekt,
og i sagens natur ved en C funktion ikke noget om objekter.

Der udover er det slet ikke sikkert at func_ptr overhovedet indeholder en
reel adresse som kan kaldes. Hvis funktionen som den peger på er en virtual
funktion, vil den formodentlig bl.a. indeholde information om hvorvidt
funktionen er virtuel og i givet fald hvilket index i den virtuelle tabel
funktionen har.
Bliv ikke fortvivlet, hvis du ikke fuldt ud forstår ovenstående - det
væsentlige budskab er at en pointer til en member funktion ikke blot er en
pointer.
Altså
sizeof(void (*)()) != sizeof(void (foo::*)())


Venlig hilsen

Mogens Hansen



Ole Nielsby (04-10-2003)
Kommentar
Fra : Ole Nielsby


Dato : 04-10-03 15:18


Jesper Matthiesen <matthiesenjesper_fjern_dette@hotmail.com> skrev:

> [....] Hvorfor kan man ikke i dette tilfælde bruge C++'s syntaks til at
> oprette funktionspointere og så sende sådan en med. Altså noget med
>
> void (FooClass::*pointer2foo)(void);
> pt2Foo = FooClass::foo;
>
> ...hvor man så sendte pt2Foo med?

Fordi FooClass::foo har en ekstra underforstået parameter (nemlig
objektet, også kaldet this-pointeren) som C++-compileren putter
ind i kaldene til den før de andre parametre.

Det bibliotek der skal kalde din callback-funktion, kan ikke se at det
er en metode på et objekt. Biblioteket har bare en adresse på noget
maskinkode, som formodes at være en funktion med de parametre
der er specificeret for den pågældende callback, og kun dem.

Thunk-koden (som er lige så nødvendig som den er grim) indsætter
then manglende 'this'-parameter.

Hvis du bruger foo uden thunk, vil der ske det at den bliver kaldt
med noget helt andet (f.eks. en RGB-farvekode) der hvor den
forventer en peger til et FooClass-objekt. Når funktionen så
bruger en ikke-statisk variabel i objektet, vil den lægge et offset
til 'this'-parameteren (hvilket giver en lidt mere lyserød udgave
af samme farve) og gå ud fra at det er adressen på variablen. Det
vil som regel resultere i et crash, og i hvert fald ikke føre til noget
meningsfuldt.

ON/Fjern sneglen fra min svaradresse


Jesper Matthiesen (04-10-2003)
Kommentar
Fra : Jesper Matthiesen


Dato : 04-10-03 16:40

Tak til Ole og Mogens for de informative svar. Objektbegrebet, 'this' osv.
er lige pludselig blevet meget mere konkret. Og bare rolig Mogens - jeg skal
nok afholde mig fra at bruge mine egne thunks de første par år :)
-Jesper

"Ole Nielsby" <ole.nielsby@snailmail.dk> wrote in message
news:3f7ed77d$0$13184$edfadb0f@dread15.news.tele.dk...
>
> Jesper Matthiesen <matthiesenjesper_fjern_dette@hotmail.com> skrev:
>
> > [....] Hvorfor kan man ikke i dette tilfælde bruge C++'s syntaks til at
> > oprette funktionspointere og så sende sådan en med. Altså noget med
> >
> > void (FooClass::*pointer2foo)(void);
> > pt2Foo = FooClass::foo;
> >
> > ...hvor man så sendte pt2Foo med?
>
> Fordi FooClass::foo har en ekstra underforstået parameter (nemlig
> objektet, også kaldet this-pointeren) som C++-compileren putter
> ind i kaldene til den før de andre parametre.
>
> Det bibliotek der skal kalde din callback-funktion, kan ikke se at det
> er en metode på et objekt. Biblioteket har bare en adresse på noget
> maskinkode, som formodes at være en funktion med de parametre
> der er specificeret for den pågældende callback, og kun dem.
>
> Thunk-koden (som er lige så nødvendig som den er grim) indsætter
> then manglende 'this'-parameter.
>
> Hvis du bruger foo uden thunk, vil der ske det at den bliver kaldt
> med noget helt andet (f.eks. en RGB-farvekode) der hvor den
> forventer en peger til et FooClass-objekt. Når funktionen så
> bruger en ikke-statisk variabel i objektet, vil den lægge et offset
> til 'this'-parameteren (hvilket giver en lidt mere lyserød udgave
> af samme farve) og gå ud fra at det er adressen på variablen. Det
> vil som regel resultere i et crash, og i hvert fald ikke føre til noget
> meningsfuldt.
>
> ON/Fjern sneglen fra min svaradresse
>



Mogens Hansen (02-10-2003)
Kommentar
Fra : Mogens Hansen


Dato : 02-10-03 16:23



"Ole Nielsby" <ole.nielsby@snailmail.dk> wrote in message
news:<3f7b61fa$0$54873$edfadb0f@dread11.news.tele.dk>...


[8<8<8<]
> (.NET-platformen har indkapslet denne teknik i delegates...)

Kan man bruge en delegate som argument til en C funktion, der tager en
pointer til en funktion, således at .NET compileren genererer den nødvendigt
thunk ?

Et eksempel på hvordan man i Standard C++ kan opnå det samme som .NET
delegates (måske endda mere fleksibelt, idet der er understøttelse for bl.a.
globale funktioner og tilladelig type konvertering) kan ses i biblioteket
Boost.Function som iøvrigt bliver en del af næste version af C++ Standard
Library.
Se f.eks.
www.boost.org

http://www.cuj.com/documents/s=8464/cujcexp0308sutter/cujcexp0308sutter.htm
for yderligere information

Det hjælper dog ikke i forbindelse med at svare på det oprindelige
spørgsmål.

Venlig hilsen

Mogens Hansen



Søg
Reklame
Statistik
Spørgsmål : 177558
Tips : 31968
Nyheder : 719565
Indlæg : 6408922
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste