1

Вопрос: Есть ли способ применить указатель на функцию-член к intptr_t в C++?Указатель на функцию-член для intptr_t

Известные факторы:

  1. Я знаю, что указатель функции члена очень специальный один
  2. Я знаю, что функция члена проходит скрытый «этот» параметр (__thiscall).
  3. Я знаю, что sizeof (указатель функции-члена)> sizeof (intptr_t) в некоторых случаях, в этом вопросе Я говорю только о том, где это возможно, то есть в моем случае sizeof (указатель функции-функции) == SizeOf (intptr_t).
  4. И, наконец, я знаю, что указатели каста на intptr_t не являются хорошим шаблоном.

Пример кода:

class test // No inheritance, in the case I need 
    { 
    public: 
    void func(); // No virtual, or any special modifiers in the case I need 
    }; 

void main2() 
    { 
    intptr_t p = &test::func; 
    }; 

Я знаю, обходной путь, чтобы сделать этот бросок, но я не люблю его, так как он requeres переменную TEMP:

void my_way() 
    { 
    intptr_t p; 
    auto t = &test::func;  // Temp variable, I don't like the fact I need to use it, but I have no other way for now 
    p = *reinterpret_cast<intptr_t*>(&t); 
    }; 

Так вопрос как сделать трюк inline как выражение rvalue, без переменной temp (и без memcpy, которая является тем же самым).

Пример:

reinterpret_cast<??>(???_cast<??>(???_cast<??>(&test::func))) 

(я не забочусь о том, как красиво выражение будет).

------------------------- (ниже некоторые мысли о том, почему, а не вопрос) ---------- ----------------------

На этом сайте есть несколько похожих тем, но все они в основном говорят о том, «почему вы так делаете?», или «зачем вам это нужно?», и говорить об этом решает проблему для того, кто спрашивает, но не для меня.

Зачем мне этот персонал: Я пишу какую-то задачу, где я решил реализовать свой собственный механизм для динамической компоновки. Может быть несколько конкретных приложений.

В моем случае - механизм динамической связи - я хочу передать указатель на функцию другому модулю. У меня есть класс и интерфейс как отдельная структура (я знаю, есть библиотеки с таким же подходом). Все классы, использующие этот механизм, как известно, равны (никакого наследования вообще нет, поэтому нет виртуальных и т. Д.). Все это работает на x86 32 бит или не более 64 Windows, скомпилированных MSVC 2012. Поскольку интерфейс полностью изолирован от класса, он использует массив указателей. Lib передает массив в хост-процесс. И в процессе пребывания у меня это ... Это даже не «проблема», но все-таки:

inline int my_interface::func_name(int param) 
    { 
    decltype(&interface_name::func_name) temp; 
    *((intptr_t*)&temp) = reinterpret_cast<interface_name::funcs*>(interface_desc->funcs)->func_name; 
    return (reinterpret_cast<decltype(this)>(object)->*temp)(param); 
    }; 

Это встроенная функция, поэтому я хочу, чтобы это было как можно меньше, и если это возможно, я хотел бы исключить «temp», потому что я не уверен, что компилятор правильно устранит это, даже при всех оптимизации.

Другие приложения (гипотонические): - Что делать, если я хочу защитить страницу памяти, где моя функция-член находится с определенным защитником. WinAPI дает мне способ сделать это, но для этого нужен адрес страницы. Нет проблем сделать это для нормальной работы, но для участника - только с WA, которую я описал? Или есть способ? - Что делать, если я хочу исправить изображение во время выполнения? То есть найти константу и заменить ее другим? Могут быть по крайней мере несколько причин для исправления времени выполнения: процесс миграции динамических связей 2.1, обфускация кода 2.2.

Это только для заметки - читатели часто спрашивают «зачем», я не хочу обсуждать, почему, потому что, на мой взгляд, может быть много приложений, все они не для новичков, а для парней безопасности и т. д.

Я прошу не обсуждать «Зачем это делать?», «Почему бы не использовать существующий механизм для dll/boost/других libs/других языков?» в этой теме.

+0

Следует отметить, что есть дополнительный фактор: ли SizeOf (мфу) == SizeOf (intptr_t) будет зависеть от компилятора вы используете, не только типы , Посмотрите, согласен ли ваш компилятор с промежуточным нажатием на '(void *)', но вы по своему усмотрению, насколько это верно. – Mat

+2

Это не может быть сделано с помощью кастинга: Pointer-to-members могут быть переданы только другим указателям-членам, даже с 'reinterpret_cast'. К сожалению, нет ничего, что можно было бы процитировать, поскольку в стандарте указывается только, какие приведения * разрешены. Однако вы могли бы использовать «memcpy» указателя на элемент (то есть скопировать содержимое указателя на член с помощью указателя на указатель на элемент). – dyp

+1

Учитывая вашу собственную точку №4, вы можете объяснить * почему * вы хотите сделать это в любом случае? Например, пытаетесь ли вы найти способ создания универсального контейнера для mfps для произвольных объектов? – kfsone

ответ

1

Нет, спецификация не позволяет вам указывать указатели функций или указатели элементов на intptr_t. Причина этого заключается в том, что для их описания может потребоваться более одного значения данных intptr_t. Например, указатели-члены на gcc имеют длину 3 intptr_t, а MSCV - от 1 до 4 intptr_t. Большая часть этого используется для обработки виртуальных функций.

На некоторых старых аппаратных средствах (что поддерживает C++) указатели также на самом деле меньше указателей на функции. Это происходит на небольших системах, где вам может потребоваться указать только на 8-битную структуру памяти, но программы загружаются в 16-разрядное пространство программной памяти.

В большинстве случаев этот шаблон, который вы пытаетесь использовать, используется для создания делегатов: указатели функций-членов постоянно привязаны к определенному объекту. Это может быть сделано с 2 ИНТ указателей и функции оберточной

struct Delegate 
{ 
    intptr_t obj; // I'll use intptr_t here, but often this is void* 
    intptr_t func; 
}; 

// you need one of these for each type of mfp you use 
static void callT_Test(intptr_t obj) 
{ 
    T* realObj = reinterpret_cast<T*>(obj); 
    realObj->test(); 
} 

// constructing a delegate to call test on t 
Delegate d; 
d.obj = reinterpret_cast<intptr_t>(&t); 
d.func = &callT_Test; 
+0

Спасибо за прямой ответ. –

+0

Я так думаю, но я не могу оставить проблему, пока не найду подтверждение. Вещь, которая меня ест: если это невозможно, тогда C++ пытается запретить мне обращаться к адресу двоичного образа функции. I.e. место, где код находится в памяти. –

+0

Более точно, C++ не предоставляет официально санкционированный способ доступа к двоичному изображению функции. Если бы он предоставил официально санкционированный способ сделать это, это ограничило бы использование C++ платформами, которые отвечают требованиям этого официально санкционированного метода.Например, некоторые из этих встроенных платформ фактически запрещают доступ к двоичному изображению кода (они называются Harvard Architectures). Теперь, если вы готовы загрязнить свои руки и быть конкретными компиляторами и платформами, существуют конкретные способы компилятора сделать то, что вы хотите. –