четверг, 1 октября 2009 г.

Функция без явного определения

Убойный для меня пример.
typedef int (*pf)(int, int);
char c[] = {85,-119,-27,-117,69,12,3,69,8,93,-61,-112};
pf sum = (pf)c; //reinterpret_cast отказывается, поэтому так.
cout << sum(2,3); //Вывод 5.


* This source code was highlighted with Source Code Highlighter.
Теперь sum - функция сложения, являющаяся аналогом этой:
int sum(int a, int b){return a+b;}

Сначала я написал нормальную функцию sum, затем байт за байтом просмотрел ее содержимое в памяти. К сожалению sizeof к функциям неприменим, поэтому я, после sum, определил еще одну функцию, и предположил, что в памяти они тоже рядом. Их адреса различались на 12 байт.

UPD: Одной строкой:
cout << ((int (*)(int, int))"\x55\x89\xE5\x8B\x45\x0C\x03\x45\x08\x5D\xC3\x90")(2,3);

Функции

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

Повторюсь, что я веду этот блог не как учебное пособие, а пытаюсь объяснить самому себе сложные моменты (написание топика заставляет достаточно подробно вникнуть в суть), а так же необычные вещи удивившие меня. Еще я люблю очень маленькие(особенно в одну строчку :), но показательные примеры.

Вопрос которым я задался: можно ли вызвать функцию, имея только ее адрес хранящийся в long. Разумеется просто ради интереса, без практической пользы. Без reinterpret_cast обойтись явно не смогу. Еще понадобится тип функции.


char f(){return 'f';}

typedef char (*PF)(); //именно такой тип у f()

long a = reinterpret_cast<long>(f); //получаем число...
cout << (reinterpret_cast<PF>(a))(); //... говорим, что это число - указатель на функцию. Скобки () приводят вызову функции.