Что хранится в указателе на виртуальный метод класса в C++ Builder (содержимое __thunk__ )?

Собственно, главный вопрос в том, почему содержимое указателей на виртуальный метод, возвращающий пользовательский класс отличается от других указателей на вируальные методы?
class Bar{
};

struct Baz {
    int a;
    int b;
    int c;
};

class Foo {
    public:
    	virtual void 	VirtualVoid(){}
        virtual int 	VirtualInt(){}
        virtual char*	VirtualCharPtr(){}
        virtual double	PureVirtualDouble() = 0;
        virtual Bar	VirtualEmptyClass() {}
        virtual Baz    VirtualNotEmptyClass(){}
        virtual long long  PureVirtualLongLong() = 0;
};


Отладчик:
foo_ptr_0: void        (Foo::*)() :0018FF48 __thunk__ [B,0,1,0]{0,0}
foo_ptr_1: int         (Foo::*)() :0018FF3C __thunk__ [B,0,5,0]{4,0}
foo_ptr_2: char*       (Foo::*)() :0018FF30 __thunk__ [B,0,9,0]{8,0}
foo_ptr_3: double      (Foo::*)() :0018FF24 __thunk__ [B,0,D,0]{12,0}
foo_ptr_4: Bar         (Foo::*)() :0018FF18 __thunk__ [B,0,11,4]{16,0}
foo_ptr_5: Baz    (Foo::*)() :0018FF0C __thunk__ [B,0,15,4]{20,0}
foo_ptr_6: long long (Foo::*)() :0018FF00 __thunk__ [B,0,19,0]{24,0}


компилятор, флаги все стандартные;
bcc32 --version
Embarcadero C++ 6.60 for Win32 Copyright (c) 1993-2013 Embarcadero Technologies, Inc.
Revision 6.60.4846.33249


Из того, что откопал:
Первое поле, которое у всех "B" - это, похоже, индекс соглашения о вызове.
При компиляции с разными флагами для указателя foo_ptr_4:
Pascal (__pascal) (-p) 
foo_ptr_4 __thunk__ [C,0,11,0]{16,0}
C (__cdecl) (-pc)
foo_ptr_4 __thunk__ [B,0,11,4]{16,0}
_msfastcall (__msfastcall) (-pm)
foo_ptr_4 __thunk__ [I,0,11,4]{16,0}
Fastcall(register)  (__fastcall) (-pr)
foo_ptr_4 __thunk__ [D,0,11,0]{16,0}
stdcall (__stdcall) (-ps)
foo_ptr_4 __thunk__ [F,0,11,4]{16,0}

Отсюда видно что четвертое поле нулевое при __pascal и __stdcall вызове.

Третье поле, наверное, смещенение от начала объекта на указатель функции:
Borland compilers add an offset of 1 to data member pointers in order to distinguish a
pointer to the first data member from a NULL pointer, represented by 0. The other compilers
have no offset, but represent a NULL data member pointer by the value -1.
  • Вопрос задан
  • 183 просмотра
Пригласить эксперта
Ответы на вопрос 1
@Mercury13
Программист на «си с крестами» и не только
Это сколько нужно байтов стека. В случае void* ничего возвращать не нужно. В случае int, char*, возвращаемое значение лежит в eax. В случае double — на верхушке стека сопроцессора. А в случае пользовательского класса — где-то в стеке вызовов. Класс Baz пустой, только указатель на ТВМ — потому 4 байта. Для класса Bar посмотри ради интереса sizeof — почти уверен, что те же 4 байта.
Возможно, когда добавим локальных переменных, эта цифра тоже увеличится.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы