Где именно указывают указатели на функцию?
Учитывая, что все примитивные типы данных и объекты имеют выделенную память, интуитивно легко представить указатели на эти типы.
Но где именно указывают указатели на функции? Учитывая, что инструкции преобразуются в машинный код и находятся в памяти, следует ли считать, что они указывают на расположение памяти, соответствующее началу команд функций?
Мы сталкиваемся со многими ошибками в указателях из-за незаконного доступа к памяти. Случается ли это, что ошибки возникают, когда указатели функций указывают на память данных вместо памяти команд?
Ответы
Ответ 1
Указатель функций также указывает на память, единственное различие заключается в том, что вместо этого есть исполняемый код в этой ячейке памяти.
На многих платформах, если вы пытаетесь выполнить данные (например, в обычной памяти), вы будете разбивать или вызывать исключение. Это известно как "Предотвращение выполнения данных" - это мера безопасности, предотвращающая непреднамеренный запуск приложений из-за вредоносного кода.
Ответ 2
Это кодовый указатель. Он указывает на адрес функции. Это по сути, как вы описали. И да, если у вас есть указатели, которые не указывают на то, что вы ожидаете, у вас будут проблемы.
Ответ 3
Указатели функций указывают на адрес функции в памяти.
В зависимости от того, как обычно назначаются указатели на функции, я был бы удивлен, если бы вы указали на местоположение данных. Они обычно не отбрасываются и поэтому вряд ли указывают куда угодно, кроме действительной функции. Если вы их много набрасываете, это может быть проблемой. Скорее всего, что данные, которые вы передаете функции, неверны.
Ответ 4
Указатель функции содержит адрес функции - что бы то ни было для данной системы. Вы можете использовать его для косвенной функции, вы можете назначить и сравнить значения указателя функции. Вы также можете преобразовать указатель на другой тип указателя на функцию и т.д.
Самый простой способ для компилятора реализовать указатель функции - это адрес памяти функции, и большинство компиляторов делают это именно так, но стандарт языка не указывает этого. Некоторые системы (я думаю, IBM AS/400 - пример) хранят дополнительную информацию в указателях функций. Компилятор может реализовать указатели на функции в виде целых индексов в таблицу дескрипторов, если требуемая семантика реализована должным образом.
Невозможно разыменовать указатель на функцию. Для вызова функции требуется указатель, а не имя функции, как его префиксное выражение; если вы используете имя функции, это имя неявно преобразуется в указатель (насколько это касается языка, сгенерированный машинный код может быть другим). Таким образом, нет никакого переносного способа для программы, чтобы определить, действительно ли указатели на функцию содержат адреса памяти или нет.
Не переносимо, учитывая функцию func
, вы можете сделать что-то вроде:
printf("Address of func is %p\n", (void*)func);
и вы, вероятно, увидите что-то похожее на удобочитаемое для человека представление адреса памяти. Но, строго говоря, поведение преобразования указателя функции на void*
не определяется языком, и оно может не работать в некоторых системах.
Возможно, вы даже сможете преобразовать указатель на unsigned char*
и изучить код машинного кода, но он выходит далеко за рамки любого, определенного стандартом C.
Лучше всего рассматривать указатели функций как непрозрачные значения, которые относятся к определенным функциям каким-то неопределенным образом.
Ответ 5
Ну, я не уверен, но учитывая, что функции - это инструкции (ADD, SUB, JMP) и что каждый из них имеет шестнадцатеричные значения, я считаю, что вы не будете изменять функцию, а только инструкцию JMP()..