Philippe Mori
В Си нет простого способа сделать это. Конечно, вы можете написать ассемблерный код для динамического создания функции с заданным аргументом (при условии, что вам разрешено писать такой код в вашей среде разработки).
С другой стороны, возможно, Вам это и не нужно. Обычно у вас есть статическая функция, принимающая аргумент экземпляра в вашей структуре, и эта функция вызывает функцию-член этого экземпляра.
Неясно, пишете ли вы код на C или C++. Если вы пишете код на языке Си, то у вас все равно нет функции-члена, так что делать такие вещи бессмысленно. Если вы пишете код на C++, то в любом случае вам следовало бы использовать new вместо malloc...
Кроме того, это выглядит странно, что вы хотите установить указатель функции в struct point на глобальную функцию.
Очевидно, что это то, что вы хотите сделать, тогда это чрезвычайно просто (предполагая C++):
struct Foo
{
void(*Print)(void* Instance);
void PrintMe() { (*Print)(this); }
};
Если вы действительно хотите сделать это по-другому, то у вас будет статический член, принимающий параметр, который будет интерпретироваться как экземпляр:
struct Foo2
{
static void PrintFuction(void *instance)
{
reinterpret_cast<foo2>(instance)->PrintMember();
}
static void PrintMember() { /* code here */ }
};
Кстати, в другом языке, таком как C#, компилятор, по сути, сгенерировал бы класс с данными в его членах. И такая функция будет представлена парой {function, instance}.
Кроме того, в современном C++ у вас также есть такой объект функции.
Таким образом, неясно, чего вы пытаетесь достичь с помощью этого, и это может быть не лучший способ сделать это... в частности, если у вас есть доступ ко всему коду.
- Обновление (2016-10-07)—
Как указано в комментариях, невозможно достичь желаемого синтаксиса, используя только стандарт C.
Что касается "обратного вызова доступа к памяти", то я об этом не знал. Я нашел следующую информацию:
http://stackoverflow.com/questions/6211429/callback-on-memory-access/6211502[
^].
Дело в том, что я могу сказать, что это специфическая функция Linux. И чтобы использовать его с целью упрощения синтаксиса, нужно было бы убедиться, что он использует правильное соглашение о вызовах, что любая используемая оптимизация компилятора совместима с взломом и что он никогда не захочет переносить код на какую-либо другую платформу, где такой взлом может быть невозможен.
По сути, взлом будет заключаться в том, что в некоторых конкретных случаях вы можете знать, в каком регистре или относительном расположении стека находится адрес только что вызванной функции. Исходя из этой информации, вы можете вычислить адрес "этого" и сделать любую необходимую корректировку, чтобы функция увидела правильную информацию.
И даже тогда этот взлом может привести к проблемам с отладкой, обработкой ошибок или проблемами совместимости.
Это не то, что следует использовать для регулярной разработки или просто для удобства более приятного синтаксиса. Если это то, что вы хотите, то вам следует серьезно подумать о компиляторе C++.
Такой вид взлома может быть полезен, если разработать какую-то конкретную библиотеку для конкретной платформы для таких вещей, как RTOS, профилировщики, анализаторы трассировки стека... Но если вы написали такие инструменты, то вам нужно иметь глубокое понимание вашей платформы и компилятора.
Серьезно ... использует компилятор C++!
В большинстве случаев нет смысла делать такой взлом, особенно если единственная цель - иметь более приятный синтаксис.
Очевидно, что есть так много причин, по которым он может сломаться, что это не будет стоить усилий. На самом деле, если ваше приложение выходит из строя или ведет себя неправильно после этого, вы понятия не имеете, вызвана ли проблема взломом, и нет простого способа проверить его, так как вам придется отменить все изменения, внесенные вами для улучшения кода.
Альтернатива
Вы можете использовать компилятор C++, способный генерировать код на языке Си. Видеть
http://stackoverflow.com/questions/3311563/do-all-c-compilers-generate-c-code[
^] для получения дополнительной информации.