Во-первых, язык С++ не позволяет получть указатель на метод класса без явного использования оператора '&'. Поэтому правильно так
Method m(&b, &B::F1);
(это для любителей изучать язык по ошибкам (и глюкам) компиляторов).
Во-вторых, чтение аргумента типа "указатель на метод класса" через 'va_arg(..., void*)' является банальным хаком, ибо приводит к неопределенному поведению (это к вопросу о приведении типов "без хака").
Во-третих, давай, продемонстрируй нам, как же ты собрался вызывать методы классов через твой "указатель" Я думаю тут никому не составить труда привести тебе хрестоматийный уже пример из пяти-десяти строк, на котором твой "указатель" быстро и громко сядет в лужу
Hello, А.Якубовский!
You wrote on Wed, 22 Dec 2004 08:41:16 GMT:
А>
[Sorry, skipped]
А> теперь внимание ответ.
А> [code]
А> struct Method {
А> void* mthdOwner;
А> void* mthdFunction;
А> Method(void* Owner,...)
А> {
А> va_list mthd;
А> va_start(mthd,Owner);
А> mthdOwner = Owner;
А> mthdFunction = va_arg(mthd,void*);
А> va_end(mthd);
А> }
А> };
А> Ну и где то в коде
А> B b;
А> Method m(&b,B::F1);
А>
А> И теперь пусть хоть кто-то скажет что нельзя привести указатель на А> функцию к типу войд*, или другому типу
Я вам скажу, что Вы облажались Я тоже могу написать
void* tmp = reinterpret_cast<void*>(&A::F1);
, но знаете, как бы я не изгалялся это будет undefined behaviour. То же самое вы и имеете в Вашем случае — вам удалось заставить это работать в частном случае. Надеюсь Вадим Никулин развеял ваши заблуждения.
Здравствуйте, А.Якубовский, Вы писали:
АЯ>Во первых никогда не встречал чтоб указатель на 32-битной платформе был больше 32 АЯ>А вам блин еще и подай как маршалинг у меня реализован на основе этого кода. Я блин парился всю ночь, по дружные издевки, а потом дайте мне плз. реализацию маршалинга. Ребята не по взрослому получается.
И не говори! Совсем не по-взрослому. Это даже не детский сад. И даже не yasli
Ну ничего. Даже после 14 лет практики можно узнать много нового
Кстати. 14 лет назад ты для какой платформы писал? Win16, DOS, MacOS, VAX? Удивительно, что ты не столкнулся с тем фактом, что нельзя приводить указатели на данные и на функции.
PS.
Обычно код, над которым пишут в угаре, — работает только с бодуна.
Здравствуйте, А.Якубовский, Вы писали:
G>>Ээээ.. G>>1) А как теперь пользотвать этот класс мэтода? G>>2) Что случится если sizeof(void*) < sizeof(void A::*) ?
АЯ>Во первых никогда не встречал чтоб указатель на 32-битной платформе был больше 32
Век живи — век учись. На 32-хбитной платформе битовый размер легального указателя на метод класса всегда строго больше 32-х бит. Например, на платформе MSVC++ указатель на метод класса, корректно работающий в условиях множественного наследования имеет размер 64 бита. Это и есть та причина, по котрой вопросы приведения указателя на метод класса к типу 'void*' не заслуживают никакого серъезного рассмотрения.
Не ну вы че издеваетесь. Мне пофиг вопрос был задекларирован. Я дал Вам на него ответ, Функции у меня вызываются на ура, и с виртуальным наследованием и без. Как у вас будут вызываться я не знаю это не мое дело. Читайте тему топика. Можно ли привети указатель на функцию к типу войд*, я не собирался распространяться на тему как использовать это дальше.
Здравствуйте, А.Якубовский, Вы писали:
АЯ>Здравствуйте, Glоbus, Вы писали:
G>>Здравствуйте, А.Якубовский, Вы писали:
G>>Ээээ.. G>>1) А как теперь пользотвать этот класс мэтода? G>>2) Что случится если sizeof(void*) < sizeof(void A::*) ?
АЯ>Во первых никогда не встречал чтоб указатель на 32-битной платформе был больше 32
Указатели разные бывают... Нет никакой гарантии, что указатель на функцию будет иметь тот же размер что и обычный указатель на память. А если ты чего-то не встречал это не значит что его нет.
АЯ>А вам блин еще и подай как маршалинг у меня реализован на основе этого кода. Я блин парился всю ночь, по дружные издевки, а потом дайте мне плз. реализацию маршалинга. Ребята не по взрослому получается.
А мы тут все скопом жестко щас наживетмся на тебе и твоем маршалинге
Ближе к делу. Если уж ты так реально парился, здается мне что парился ты зря, хотя бы потому, что можно одним движением руки избавиться от вопроса sizeof(void*) < sizeof(void A::*)
E>Результат работы под VC++ 7.1: E>sizeof(vp): 4, sizeof(mp): 4
Такой результат ты получишь только при "агрессивных" установках компиляции, при которых указатели на методы классов в MSVC++ в общем случае работают некорректно. При включении "нормальных" установок компиляции размер указателя на метод класса становится равным 16. Есть "промежуточная" установка, при котором размер будет равен 8.
Здравствуйте, А.Якубовский, Вы писали:
АЯ>Здравствуйте, Кодт, Вы писали:
АЯ>Не ну вы че издеваетесь. Мне пофиг вопрос был задекларирован. Я дал Вам на него ответ, Функции у меня вызываются на ура, и с виртуальным наследованием и без. Как у вас будут вызываться я не знаю это не мое дело. Читайте тему топика. Можно ли привети указатель на функцию к типу войд*, я не собирался распространяться на тему как использовать это дальше.
Ты че, друг! Хочешь, чтобы IT-индустрия простаивала из-за тебя целый день, пытаясь доказать, что твое решение не работает? Ты пробовал вызывать ЭТО для классов с виртуальным наследованием?
Читай еще раз здесь
Здравствуйте, А.Якубовский, Вы писали:
АЯ>Здравствуйте, Кодт, Вы писали:
АЯ>Не ну вы че издеваетесь.
Какие издевки.
Не дай бог юзать софт, или еще хуже сопровождать такой
код, где что-то иногда, в очень частных случаях работает.
Я за свои 7 лет опыта (меньше твоего) уже устал
бороться с такими и подобными хаками, хуками и прочими подобными прелестями.
Зачем делать через задницу, когда есть нормальные надежные решения.
Но это уже полный уход от темы.
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Здравствуйте, eao197, Вы писали:
E>>Результат работы под VC++ 7.1: E>>sizeof(vp): 4, sizeof(mp): 4
АТ>Такой результат ты получишь только при "агрессивных" установках компиляции, при которых указатели на методы классов в MSVC++ в общем случае работают некорректно. При включении "нормальных" установок компиляции размер указателя на метод класса становится равным 16. Есть "промежуточная" установка, при котором размер будет равен 8.
Запускал компиляцию так:
cl -GX meth_ptr_size.cpp
Потом просто запустил meth_ptr_size.exe
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, jazzer, Вы писали:
J>Боюсь, что мы сейчас увидим решение с ..., thunks в стиле ATL или еще что-нть непереносимое.
Решение, как видишь, уже опубликовано и включает банальное силовое (и, разумеется, некорректное) приведение указателя на метод к типу 'void*'. Гора родила мышь. Как и следовало ожидать, автор решения наивно полагает, что указатель на метод класса состоит только из адреса точки входа в метод
То г-н Тарасевич, крутой спец по с++, теорик. Никогда не "бравший" в руки отладчик типа Soft Ice или хотя-бы встроенный. Вам как особо одаренному поясню После линковки, в теле программы идет вызов следующего типа. Извините что испоганю асмом ваш любимы С++, но все же
mov ecx, this — я пишу в некотором отступлении от стандартного асма, но что одаренным C++ программистам было понятно
mov eax, dword ptr [ecx+4] — это к примеру вызов виртуального метода +4 это адресс виртуальной функции в таблице vtbl
...
push param1
push param2
push param3
push ecx неявная передача this через стек
call eax
....
Так вот если-б вы зоть раз соизволили сделать трасировку в асме, ВЫ бы подумали прежде чем написать что указатель может быть больше 32
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Век живи — век учись. На 32-хбитной платформе битовый размер легального указателя на метод класса всегда строго больше 32-х бит. Например, на платформе MSVC++ указатель на метод класса, корректно работающий в условиях множественного наследования имеет размер 64 бита. Это и есть та причина, по котрой вопросы приведения указателя на метод класса к типу 'void*' не заслуживают никакого серъезного рассмотрения.
Во! Точно! Я не мог вспомнить, в каких случаях получается 128-битный указатель... Виртуальное наследование + множественное наследование + виртуальные функции. Вуаля!
Здравствуйте, А.Якубовский, Вы писали:
АЯ>Здравствуйте, Кодт, Вы писали:
АЯ>Не ну вы че издеваетесь. Мне пофиг вопрос был задекларирован. Я дал Вам на него ответ, Функции у меня вызываются на ура, и с виртуальным наследованием и без. Как у вас будут вызываться я не знаю это не мое дело. Читайте тему топика. Можно ли привети указатель на функцию к типу войд*, я не собирался распространяться на тему как использовать это дальше.
Держите меня трое И у этого человека 14 лет опыта в Си и Си++
Старик, то что ты сделал это не привдение типа — это не приведение типа. Просто потому что нельзя привести тип void* к типу указателя на функцию. А то что там у тебя — это просто запись в стек sizeof(void B::*) байт и выгребалово sizeof(void*) байтю А куда же остальные sizeof(void B::*) — sizeof(void*) байт деть?
Здравствуйте, А.Якубовский, Вы писали:
АЯ>Не ну вы че издеваетесь. Мне пофиг вопрос был задекларирован. Я дал Вам на него ответ, Функции у меня вызываются на ура, и с виртуальным наследованием и без. Как у вас будут вызываться я не знаю это не мое дело. Читайте тему топика. Можно ли привети указатель на функцию к типу войд*, я не собирался распространяться на тему как использовать это дальше.
Ну ради бога. У тебя компилируется и работает. Только я твои программы на свой компьютер не пущу.
"Неправильный ответ — тоже ответ" (по аналогии с отрицательным результатом).
Hello, А.Якубовский!
You wrote on Wed, 22 Dec 2004 09:09:03 GMT:
А> Не ну вы че издеваетесь. Мне пофиг вопрос был задекларирован. Я дал Вам А> на него ответ, Функции у меня вызываются на ура, и с виртуальным А> наследованием и без. Как у вас будут вызываться я не знаю это не мое А> дело. Читайте тему топика. Можно ли привети указатель на функцию к А> типу войд*, я не собирался распространяться на тему как использовать А> это дальше.
Мне кажеться Вы непоняли — в С++ приводить типы можна какие угодно к каким угодно. Но от этого программа не остается правильной, а неправильные программы могут представлять только академический интерес, уж ни как не промышленный. А зачем нам кони в вакууме? Правильно, незачем. А доказательство в стиле "это у меня работает" никогда не было таковым.
Здравствуйте, А.Якубовский, Вы писали:
АЯ>mov ecx, this — я пишу в некотором отступлении от стандартного асма, но что одаренным C++ программистам было понятно АЯ>mov eax, dword ptr [ecx+4] — это к примеру вызов виртуального метода +4 это адресс виртуальной функции в таблице vtbl АЯ>...
АЯ>push param1 АЯ>push param2 АЯ>push param3 АЯ>push ecx неявная передача this через стек АЯ>call eax
АЯ>....
АЯ>Так вот если-б вы зоть раз соизволили сделать трасировку в асме, ВЫ бы подумали прежде чем написать что указатель может быть больше 32
Душит смех. Нет, молодой человек, если бы Вы хоть раз сделали трассировку правильно откомпилированной программы "в АСМЕ" и поcмотрели, как выглядит вызов метода класса через корректно сформированный указатель на метод класса, Вы бы никогда не стали писать здесь всю эту белиберду и публично садиться в лужу еще и с "асмом".
Специально для Вас я приведу здесь очень показательный пример этого самого "асма" для вызова метода класа через указатель.
Вот С++ код
#include <iostream>
struct A {
int i;
A() : i(1) {}
void print() { std::cout << i << std::endl; }
};
struct B {
int i;
B() : i(2) {}
void print() { std::cout << i << std::endl; }
};
struct C : A, B {
int i;
C() : i(3) {}
};
void call(C* pc, void (C::*pm)()) {
(pc->*pm)();
}
int main() {
C c;
call(&c, &A::print);
call(&c, &B::print);
}
Поясню: обе выделенные жирным инструкции занимаются чтением частей указателя 'pm', который располагается в стеке по адресам esp+4 и esp+8. Советую вам тщательно разобрать этот код и хорошенько подумать о том, что же делают эти две инструкции и почему же это они читают из 32-хбитного (как Вы полагаете) указателя 64 бита информации.
Здравствуйте, А.Якубовский, Вы писали:
АЯ>у меня наследование такое. И все чудно работает
Покажи полный код рабочего примера. Без урывочков...
Кстати, специально для любителей отладки. Вот, соорудил из твоих кусочков:
#include <stdio.h>
#include <stdarg.h>
class A
{
public:
void __stdcall Fn1()
{
printf("A::Fn1()\n");
}
virtual void __stdcall Fn2() = 0;
};
class B : public virtual A
{
public:
void __stdcall Fn1(int& k,int& d)
{
printf("B::Fn1(%d-%d)\n",k,d);
}
virtual void __stdcall Fn2()
{
printf("B::Fn2()\n");
}
};
struct Method
{
Method(void* Owner,...)
{
va_list mthd;
va_start(mthd,Owner);
mthdOwner = Owner;
unsigned long tag1 = va_arg(mthd,unsigned long);
mthdFunction = va_arg(mthd,void*);
unsigned long tag2 = va_arg(mthd,unsigned long);
printf("owner = %p, tag1 = %08X, func = %p, tag2 = %08X\n", mthdOwner, tag1, mthdFunction, tag2);
va_end(mthd);
// dump the stack again...
printf("Ellipsis is ...\n");
va_start(mthd,Owner);
do
{
tag2 = va_arg(mthd,unsigned long);
printf("... %08X\n", tag2);
}
while(tag2 != 0xDEADBEEF);
va_end(mthd);
}
};
int main()
{
B b;
Method m(&b, 0xFEEDFACE, &B::Fn2, 0xDEADBEEF);
}
Вывод:
owner = 0012FF78, tag1 = FEEDFACE, func = 004011A0, tag2 = 00000000 <--- а где же дохлая корова?
Ellipsis is ...
... FEEDFACE
... 004011A0
... 00000000
... 00000004
... DEADBEEF <--- а вот она!
Перекуём баги на фичи!
Re[3]: Указатель на функцию
От:
Аноним
Дата:
22.12.04 10:01
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:
Ну извините всех кого я обидел. Я так понимаю модератор меня забанил. Но еще раз повторюсь без эмоций, вопрос стоял так Можно ли привети указатель к типу войд*. Я специально поставил вопрос таким образом, чтобы можно было понять впринципе возможно ли приведение типов функций. Я для себя ответ нашед можно. Здесь я опубликовал именно ответ на свой вопрос о приведении к типу войд*.
Теперь дабы достичь консенсуа а приведу код который действительно у меня написан.
Обратите пожалуйста внимание на __stdcall. Я готов пообсуждать без эмоций в чем я не прав. Токо пжалуйста не надо стучать себя кулоком в грудь и говорить что тут полный бред.