Замысловатая задачка по С++

Модератор: Модераторы разделов

Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Замысловатая задачка по С++

Сообщение flook »

Есть класс

Код: Выделить всё

class A
{
public:
       void fn(void);
};

void A::fn(void)
{
       printf("Hello world\n");
}

Есть функция main:

Код: Выделить всё

int main(void)
{
         void (*pfn)(void);

         pfn = get_a_fn_ptr();
         pfn();
         return 0;
}

Требуется так реализовать get_f_fn_ptr() чтобы вызов через указатель увенчался успехом.
Это просто головоломка, так что вопросы "а нафига" просьба не задавать :)
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
v04bvs
Сообщения: 636
ОС: Debian GNU/Linux

Re: Замысловатая задачка по С++

Сообщение v04bvs »

Код: Выделить всё

bvs@debian:~$ cat test.cpp
#include <iostream>
using std::cout;
using std::endl;

class A
{
public:
        static void anchor( );
        void fn( );
};

void A::anchor( )
{
}

void A::fn( )
{
        cout << "Hello, world\n";
}

typedef void (*FunPtr)();

FunPtr get_f_ptr( )
{
        char *p = reinterpret_cast<char*>(&A::anchor);
        p += 12;
        return reinterpret_cast<FunPtr>(p);
}

int main( )
{
        FunPtr fp = get_f_ptr();
        fp();
        return 0;
}
bvs@debian:~$ g++ test.cpp
bvs@debian:~$ ./a.out
Hello, world
bvs@debian:~$ g++ --version
g++ (GCC) 4.0.3 (Debian 4.0.3-1)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

bvs@debian:~$


К сожалению других доказательств нету, магическая цифра 12 была подобрана перебором, даже при компиляции с оптимизацией по размеру ничего не работает, я уже не говорю про другие компиляторы и системы.

Нормального пути я не нашел, конечно, если сделать метод класса статическим, проблем не возникает, но так, как сформулировано в заданиии - получилось только так.
С большим интересом посмотрю на правильное решение (если конечно оно существует, по стандарту его не должно быть :))
Спасибо сказали:
Аватара пользователя
x-term
Сообщения: 3

Re: Замысловатая задачка по С++

Сообщение x-term »

Это как это без экземпляра класса вызвать нестатическую функцию? Да еще и чтоб работало с любым компилятором?
Спасибо сказали:
Аватара пользователя
Zeus
Сообщения: 694

Re: Замысловатая задачка по С++

Сообщение Zeus »

x-term писал(а):
20.03.2006 20:45
Это как это без экземпляра класса вызвать нестатическую функцию? Да еще и чтоб работало с любым компилятором?

Да, фигня какая-то.
Может и отработает, но измени класс и уже никаких гарантий.
А если вызываемая функция обращается к переменным класса? Что тогда будет?
Спасибо сказали:
Аватара пользователя
oav
Бывший модератор
Сообщения: 296

Re: Замысловатая задачка по С++

Сообщение oav »

v04bvs писал(а):
20.03.2006 20:30
К сожалению других доказательств нету, магическая цифра 12 была подобрана перебором, даже при компиляции с оптимизацией по размеру ничего не работает, я уже не говорю про другие компиляторы и системы.

Нормального пути я не нашел, конечно, если сделать метод класса статическим, проблем не возникает, но так, как сформулировано в заданиии - получилось только так.
С большим интересом посмотрю на правильное решение (если конечно оно существует, по стандарту его не должно быть :))

Указатель на член класса, в зависимости от платформы и компилятора (включая даже разные версии одного и тогоже компилятора) имеет размер от 8 до 20 байт. Решение задачи стандартными и переносимыми способами не существует. Если все-таки ее надо решить в реальнойсти, то можно почитать Fast Delegats на codeproject.com или вообще взять boost::function через boost::bind - что позволит получить симантику вызова обычной функции, а в реальности вызовется мембер класса (через бинд привезать this)

oav писал(а):
21.03.2006 11:13
v04bvs писал(а):
20.03.2006 20:30

К сожалению других доказательств нету, магическая цифра 12 была подобрана перебором, даже при компиляции с оптимизацией по размеру ничего не работает, я уже не говорю про другие компиляторы и системы.

Нормального пути я не нашел, конечно, если сделать метод класса статическим, проблем не возникает, но так, как сформулировано в заданиии - получилось только так.
С большим интересом посмотрю на правильное решение (если конечно оно существует, по стандарту его не должно быть :))

Указатель на член класса, в зависимости от платформы и компилятора (включая даже разные версии одного и тогоже компилятора) имеет размер от 8 до 20 байт. Решение задачи стандартными и переносимыми способами не существует. Если все-таки ее надо решить в реальнойсти, то можно почитать Fast Delegats на codeproject.com или вообще взять boost::function через boost::bind - что позволит получить симантику вызова обычной функции, а в реальности вызовется мембер класса (через бинд привезать this)

Да еще размер указателя зависит от множественнего наследования, виртуального насладевания и наличия виртуальных функций - т.е. число 12 будет различаться даже для разных классов ;)
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Замысловатая задачка по С++

Сообщение flook »

Насчет фигни какой-то - конечно фигня и в реальной жизни так делть не надо, но это же просто головоломка.

Насчет "если вызываемая функция обращается к переменным класса" - ЭТА функция не обращается, а задачка именно про нее. Если обращается - будет segmentation fault (я лично проверил).

Насчет "сделать статической" - это конечно да, но тогда теряется изюминка :)

Насчет эмпирической константы - это, конечно, некрасиво, но, в общем, правильно.

Раз народу задачка понравилась - я в пятницу опубликую "правильный" ответ. Правильность его в том, что он не замешан на эмпирику, не зависит от изменений в классе (при условии, что прототип функции сохранен) и, вроде как, ни в одной строке не противоречит синтаксису :)

А пока - принимаю варианты :)

oav писал(а):
21.03.2006 11:13
Указатель на член класса, в зависимости от платформы и компилятора (включая даже разные версии одного и тогоже компилятора) имеет размер от 8 до 20 байт. Решение задачи стандартными и переносимыми способами не существует. Если все-таки ее надо решить в реальнойсти, то можно почитать Fast Delegats на codeproject.com или вообще взять boost::function через boost::bind - что позволит получить симантику вызова обычной функции, а в реальности вызовется мембер класса (через бинд привезать this)

Да еще размер указателя зависит от множественнего наследования, виртуального насладевания и наличия виртуальных функций - т.е. число 12 будет различаться даже для разных классов ;)

И тем не менее платформонезависимое решение есть :)
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
Zeus
Сообщения: 694

Re: Замысловатая задачка по С++

Сообщение Zeus »

flook писал(а):
21.03.2006 11:22
И тем не менее платформонезависимое решение есть :)

А оно в стиле С++ или просто такие же извороты как "+12"?
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Замысловатая задачка по С++

Сообщение flook »

Zeus писал(а):
21.03.2006 12:16
flook писал(а):
21.03.2006 11:22

И тем не менее платформонезависимое решение есть :)

А оно в стиле С++ или просто такие же извороты как "+12"?

Ну как сказать... Оно в рамках синтаксиса и без эмпирических констант и тайных знаний о внутреннем устройстве класса. А так - конечно такие вещи только изворотами и делают...
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
oav
Бывший модератор
Сообщения: 296

Re: Замысловатая задачка по С++

Сообщение oav »

flook писал(а):
21.03.2006 11:22
Насчет фигни какой-то - конечно фигня и в реальной жизни так делть не надо, но это же просто головоломка.

Насчет "если вызываемая функция обращается к переменным класса" - ЭТА функция не обращается, а задачка именно про нее. Если обращается - будет segmentation fault (я лично проверил).

аа, фсе, утираю руки - тады это не инетересно.
Тем, кому это все-таки интересно с реально-практичной точки зрения могу порекомендовать
http://www.codeproject.com/cpp/FastDelegate.asp
Спасибо сказали:
Аватара пользователя
d_Sun
Сообщения: 291

Re: Замысловатая задачка по С++

Сообщение d_Sun »

oav - большое спасибо за ссылку.
Моя подпись сильно длинная :)
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Замысловатая задачка по С++

Сообщение flook »

oav писал(а):
21.03.2006 14:38
flook писал(а):
21.03.2006 11:22

...
Если обращается - будет segmentation fault (я лично проверил).

...
http://www.codeproject.com/cpp/FastDelegate.asp

ММ! Ну теперь я знаю как заставить мой пример не падать в случае обращения к this :)

oav писал(а):
21.03.2006 11:13
Если все-таки ее надо решить в реальнойсти, то можно почитать Fast Delegats на codeproject.com или вообще взять boost::function через boost::bind - что позволит получить симантику вызова обычной функции, а в реальности вызовется мембер класса (через бинд привезать this)

Код функции get_a_fn_ptr() привести можете?
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
oav
Бывший модератор
Сообщения: 296

Re: Замысловатая задачка по С++

Сообщение oav »

flook писал(а):
21.03.2006 15:35
oav писал(а):
21.03.2006 11:13

Если все-таки ее надо решить в реальнойсти, то можно почитать Fast Delegats на codeproject.com или вообще взять boost::function через boost::bind - что позволит получить симантику вызова обычной функции, а в реальности вызовется мембер класса (через бинд привезать this)

Код функции get_a_fn_ptr() привести можете?

Нет, конечно. :rolleyes:
Но еслиб нужна была симантика сишного вызова, а бы использовал, как и говорил выше, boost::function c всязке в биндом. такой код могу привести, если надо - чтобы его привести не нужно изучать ничего, проверять и т.п.

Кстати, если пошла такая пьянка, недавно написал забавную реализацию фабрики классов отталкнувшись от фабрики Александреску. Получилось забавно по С++ извращенствами и вполне удобно-эффективно. Можно устроить конкурс на эту тему - людям полезно будет, а мне по времени ничего не стоить :) Если инетересно - напишу подробности.
Спасибо сказали:
Аватара пользователя
d_Sun
Сообщения: 291

Re: Замысловатая задачка по С++

Сообщение d_Sun »

oav писал(а):
21.03.2006 16:11
Кстати, если пошла такая пьянка, недавно написал забавную реализацию фабрики классов отталкнувшись от фабрики Александреску. Получилось забавно по С++ извращенствами и вполне удобно-эффективно. Можно устроить конкурс на эту тему - людям полезно будет, а мне по времени ничего не стоить :) Если инетересно - напишу подробности.


Давайте сначала узнаем решение этой задачи...
Моя подпись сильно длинная :)
Спасибо сказали:
Аватара пользователя
Clear_Mind
Сообщения: 241
Статус: Изредко заглядывающий
ОС: openSuSE 11.1

Re: Замысловатая задачка по С++

Сообщение Clear_Mind »

Задача конечно интересная, но зачем тогда С++, если не пользоваться его возможностями.
К примеру очень мощьная вещь operator()(...) позволяет использовать объекты как
обычные функции. У Страуструпа об этом довольно много написано.

Применительно к этой задаче

Код: Выделить всё

class A {
   string s;
public:
   A(string s) {/*инициализация класса*/}
   operator()() {
      cout << s << endl; // вывод строки
   }
};

(заранее извиняюсь, что не совсем в тему ;) )
Bombers launch with no recall + Minutes warning of the missile fall
Take a look at your last sky + Guessing you won't have the time to cry
--- Iron Maiden (Brouther Than A Thousand Suns, 2006)
Спасибо сказали:
Аватара пользователя
d_Sun
Сообщения: 291

Re: Замысловатая задачка по С++

Сообщение d_Sun »

Clear_Mind писал(а):
21.03.2006 16:17
(заранее извиняюсь, что не совсем в тему ;) )


:blink: Я бы сказал совсем не в тему...
Моя подпись сильно длинная :)
Спасибо сказали:
Аватара пользователя
oav
Бывший модератор
Сообщения: 296

Re: Замысловатая задачка по С++

Сообщение oav »

d_Sun писал(а):
21.03.2006 16:17
oav писал(а):
21.03.2006 16:11

Кстати, если пошла такая пьянка, недавно написал забавную реализацию фабрики классов отталкнувшись от фабрики Александреску. Получилось забавно по С++ извращенствами и вполне удобно-эффективно. Можно устроить конкурс на эту тему - людям полезно будет, а мне по времени ничего не стоить :) Если инетересно - напишу подробности.


Давайте сначала узнаем решение этой задачи...

Конечно-конечно - ждемс. Только я почти уверен что он не будет 100% рабочим, хотя может это и не так;) но вариант с убитым this не принимается - ибо не инетерсно
Спасибо сказали:
Аватара пользователя
d_Sun
Сообщения: 291

Re: Замысловатая задачка по С++

Сообщение d_Sun »

oav писал(а):
21.03.2006 16:28
Конечно-конечно - ждемс. Только я почти уверен что он не будет 100% рабочим, хотя может это и не так;) но вариант с убитым this не принимается - ибо не инетерсно


Ну покажите хоть этот... :)
Моя подпись сильно длинная :)
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Замысловатая задачка по С++

Сообщение flook »

oav писал(а):
21.03.2006 16:28
... вариант с убитым this не принимается - ибо не инетерсно

Суть задачи не в том, чтобы написать что-то для общего пользования, а в том, чтобы проверить свое понимание устройства генерируемого ++ным компилятором кода и синтаксиса языка. В этом суть подобных задач - обход за спиной компилятора. oav, Вы можете написать эту функцию без упоминания классов "третьих лиц"? Или нет?
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
oav
Бывший модератор
Сообщения: 296

Re: Замысловатая задачка по С++

Сообщение oav »

flook писал(а):
21.03.2006 18:22
oav писал(а):
21.03.2006 16:28

... вариант с убитым this не принимается - ибо не инетерсно

Суть задачи не в том, чтобы написать что-то для общего пользования, а в том, чтобы проверить свое понимание устройства генерируемого ++ным компилятором кода и синтаксиса языка. В этом суть подобных задач - обход за спиной компилятора. oav, Вы можете написать эту функцию без упоминания классов "третьих лиц"? Или нет?

Я же ответил, что _нет_. У меня просто нет такой возможности :huh:
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Замысловатая задачка по С++

Сообщение flook »

oav писал(а):
21.03.2006 18:30
Я же ответил, что _нет_.

Тогда давайте не засорять тему :)
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
oav
Бывший модератор
Сообщения: 296

Re: Замысловатая задачка по С++

Сообщение oav »

flook писал(а):
21.03.2006 18:41
oav писал(а):
21.03.2006 18:30

Я же ответил, что _нет_.

Тогда давайте не засорять тему :)

Уговорил, первый и посл. раз участвую в "у кого пиписька длинее" :mellow:

typedef void (*pfn)(void);
pfn get_a_fn_ptr()
{

typedef void (A::*AMem )(void);

AMem bb= &A::fn;
void* cc = (*(char**)&bb);

return (pfn)cc;
}

5 минут потратил от рабочего времени :( только за сегодня свалили 20 багов, оврал полный, а тут байты гоняют, маются чем попало

VC7.1 работает
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Замысловатая задачка по С++

Сообщение flook »

oav писал(а):
21.03.2006 19:20
Уговорил, первый и посл. раз участвую в "у кого пиписька длинее" :mellow:
...
5 минут потратил от рабочего времени :( только за сегодня свалили 20 багов, оврал полный, а тут байты гоняют, маются чем попало

Мдя... :huh: Судя по тому, сколько текста до этого было запощено - аврал не полный или ушло не 5 минут ;)
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
oav
Бывший модератор
Сообщения: 296

Re: Замысловатая задачка по С++

Сообщение oav »

flook писал(а):
21.03.2006 20:08
oav писал(а):
21.03.2006 19:20

Уговорил, первый и посл. раз участвую в "у кого пиписька длинее" :mellow:
...
5 минут потратил от рабочего времени :( только за сегодня свалили 20 багов, оврал полный, а тут байты гоняют, маются чем попало

Мдя... :huh: Судя по тому, сколько текста до этого было запощено - аврал не полный или ушло не 5 минут ;)

:unsure: я доказывать ничего и никому не собираюсь, весь текст который я запостил может реально кому-то помочь, в отличии от сабжевой задачи, в которой, похоже, даже исследовательского смысла никакого нет. Странный ты какой-то, флук :-\
Спасибо сказали:
WolfON
Сообщения: 226

Re: Замысловатая задачка по С++

Сообщение WolfON »

создаем некоторый указатель до функции, потом чтобы получить реальный адрес ф-ии прибавляем к адресу указателя его размер, что будет законно для любой платформы.
ArchLinux on AXP2000+/768/ATI R9600XT
Registered Linux User 396336
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Замысловатая задачка по С++

Сообщение flook »

WolfON писал(а):
22.03.2006 13:25
создаем некоторый указатель до функции, потом чтобы получить реальный адрес ф-ии прибавляем к адресу указателя его размер, что будет законно для любой платформы.

1. talk is cheap, show me the code © Linus Torvalds
2. Это не обязательно будет работать, так как компилятор может выровнять функцию по размеру, большему размера указателя, и между указателем и функцией будет "дырка".
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Замысловатая задачка по С++

Сообщение flook »

Итак итоги.
Прислал решение v04bvs, которое грешило подобраной руками константой, снизошел ;) до нас oav, у которого решение абсолютно правильное. А вот мое решение с комментерием:

Код: Выделить всё

void (*get_a_fn_ptr(void))(void)
{
         char buf[sizeof(void *) * 2 + 3];
         void (*ret)(void);

         sprintf(buf, "%p", &A::fn);
         sscanf(buf, "%p", &ret);
         return ret;
}

Пояснение. %p печатает void * указатель в 16ричной форме, так что длина (максимаьная) будет 2 * кол-во байт в void * плюс '\0' и плюс 0x. В scanf передаются аргументы любого типа, так что компилятору параллельно сто ему туда суют.
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
oav
Бывший модератор
Сообщения: 296

Re: Замысловатая задачка по С++

Сообщение oav »

я не "нисходил", просто думал что нужно более рабочее решение, которое с кандачка не написать. а это решение не будет работать с this никогда, т.к. экземпляра класса вообще нет. :unsure:

2all: нужна кому-нить демонстрашка-задачка реализации фабрики классов, построенной на базе фабрики Александреску + одно фича-особенность. Вешь крайне полезная и необходимая почти во всех более менее крупных С++ проектах
Спасибо сказали:
Аватара пользователя
Zeus
Сообщения: 694

Re: Замысловатая задачка по С++

Сообщение Zeus »

oav писал(а):
24.03.2006 12:30
я не "нисходил", просто думал что нужно более рабочее решение, которое с кандачка не написать. а это решение не будет работать с this никогда, т.к. экземпляра класса вообще нет. :unsure:

2all: нужна кому-нить демонстрашка-задачка реализации фабрики классов, построенной на базе фабрики Александреску + одно фича-особенность. Вешь крайне полезная и необходимая почти во всех более менее крупных С++ проектах

Так если полезная - пости, чего спрашиваешь?
Спасибо сказали:
Аватара пользователя
flook
Сообщения: 585
Статус: Просто flook

Re: Замысловатая задачка по С++

Сообщение flook »

oav писал(а):
24.03.2006 12:30
я не "нисходил", просто думал что нужно более рабочее решение, которое с кандачка не написать. а это решение не будет работать с this никогда, т.к. экземпляра класса вообще нет. :unsure:

Щас матом буду :angry:
Я ж в самом начале написал - ЭТО УПРАЖНЕНИЕ ДЛЯ УМА И НИКАКОГО ПРАКТИЧЕСКОГО ПРИМЕНЕНИЯ У ЭТОЙ ЗАДАЧИ НЕТ
В каждом из нас спит гений... и с каждым днем все крепче...
Спасибо сказали:
Аватара пользователя
oav
Бывший модератор
Сообщения: 296

Re: Замысловатая задачка по С++

Сообщение oav »

flook писал(а):
24.03.2006 13:21
oav писал(а):
24.03.2006 12:30

я не "нисходил", просто думал что нужно более рабочее решение, которое с кандачка не написать. а это решение не будет работать с this никогда, т.к. экземпляра класса вообще нет. :unsure:

Щас матом буду :angry:
Я ж в самом начале написал - ЭТО УПРАЖНЕНИЕ ДЛЯ УМА И НИКАКОГО ПРАКТИЧЕСКОГО ПРИМЕНЕНИЯ У ЭТОЙ ЗАДАЧИ НЕТ

Я не говорил про реальное применение, я говорил про this - в реальности эту задачу не решить. совсем. никогда. на С++.
Матом не надо :unsure:
Спасибо сказали: