Почему не являются указателями на функции-члены только адрес памяти, такой как указатели данных

Я понял из этой записи в FAQ, что нельзя преобразовать указатель на функцию-член в/из void*. Причина, по которой указатели на элементы не являются адресами памяти, точно так же, как указатели на данные! Почему так? Пожалуйста, помогите мне получить разъяснения. И это не обязательно с функциями-членами, но любые нормальные C-функции не являются?

Ответы

Ответ 1

указатели на элементы не являются адресами памяти точно так же, как указатели на данные! Почему так?

Указатели на функции-члены должны указывать, является ли функция виртуальной, и разрешить виртуальную отправку (возможно, указав индекс в таблицу vtable, а не адрес конкретной функции), если это так. Это делает их более сложными, чем просто адрес.

И это не обязательно с функциями-членами, но любые обычные C-функции также не являются?

Указатели на "обычные" (нечленные) функции могут быть преобразованы в указатели объектов, но не переносимы. Цитирование стандарта:

С++ 11 5.2.10/8 Преобразование указателя функции в тип указателя объекта или наоборот условно поддерживается. Значение такого преобразования определяется реализацией, [...]

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

Ответ 2

В стандарте С++

Как следующий FAQ говорит:

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

В §5.2.10/8 (специально для N3936) стандарт указывает, что это действительно реализация:

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

Здесь поведение хорошо определено.

В стандарте C

В стандарте C не рассматривается преобразование указателя на указатель объекта. На самом деле, он едва рисует линию между ними.

В § 6.3.2.3/8 говорится, что:

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

В этот момент поведение почти кажется неуказанным.

И затем позже в § 6.5.9/6:

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

Здесь мы видим единственный след фактической разницы в:

Два указателя сравниваются равными тогда и только тогда, когда оба указателя [..] относятся к одной и той же функции (..) или [..].

Почему

Что касается "почему", он, по-видимому, зависит от того, что некоторые архитектуры просто имеют функции и объекты в двух адресных пространствах.