В (C и) C ++ указатели на разные типы не обязательно имеют одинаковый размер. Я бы надеялся, что void * обязательно самый большой, но, похоже, даже это на самом деле не гарантировано.

Мой вопрос: Как я могу определить, какой максимальный размер указателя на моей платформе (цели компиляции)?

Примечание: я имею в виду любой указатель, включая указатели на функции-члены класса; вещи, которые вы можете получить с помощью оператора &. Я не имею в виду сущности, которые «в разговорной речи» называются указателями, то есть не unique_ptr или shared_ptr и так далее.

6
einpoklum 18 Апр 2019 в 15:16

2 ответа

Лучший ответ

Существует четыре совершенно не связанных класса типов указателей в языке C ++: указатели объектов, указатели функций, указатели на нестатические элементы данных и указатели на нестатические функции-члены. Термин «указатель» обычно применяется только к типам указателей на объекты и функции [ basic.compound ] / 3 :

[…] За исключением указателей на статические элементы, текст, ссылающийся на «указатели», не относится к указателям на элементы. [ ... ]

Указатели и указатели на нестатические элементы фактически обрабатываются как два совершенно разных типа составных типов [basic.compound] / 1 (что имеет смысл, поскольку нестатические указатели на элементы больше похожи на относительные смещения и меньше похожи на фактические адреса).

За исключением условно поддерживаемого преобразования между указателями на объекты и функции, семантика которого (если поддерживается вообще) будет определяться реализацией [expr.reinterpret.cast] / 8, нет способа конвертировать между этими четырьмя классами типов указателей.

Однако в стандарте указывается взаимопревращаемость между указателями объектов [expr.reinterpret.cast] / 7, взаимозаменяемость между указателями функций [expr.reinterpret.cast ] / 6, взаимопревращаемость среди указателей элементов данных [expr.reinterpret .cast] /10.2 и взаимопревращаемость между указателями на функции-члены [ expr.reinterpret.cast ] /10.1.

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

Michael Kenzel 18 Апр 2019 в 16:38

Существует 3 разных типа указателей, которые могут иметь разный размер:

  • указатель на объект
  • указатель на функцию
  • указатель на функцию-член

void * гарантированно будет достаточно большим, чтобы содержать каждый указатель на объект в соответствии со стандартом C ++ 17 6.9.2.5:

Указатель на cv-qualified ([basic.type.qualifier]) или cv-unqualified void может использоваться для указания на объекты неизвестного типа. Такой указатель должен содержать любой указатель объекта. Объект типа cv void * должен иметь те же требования к представлению и выравниванию, что и cv char *.

class A;

typedef void (A::*a_func_ptr)(void);
typedef void (*func_ptr)(void);

size_t a = sizeof(a_func_ptr), b = sizeof(func_ptr), c = sizeof(void*);

std::cout << std::max(a, std::max(b, c)) << std::endl;

Должен делать свою работу.

Редактировать: C ++ 17 Standard 6.9.2.3 говорит

За исключением указателей на статические элементы, текст, ссылающийся на «указатели», не относится к указателям на элементы.

Итак, самый большой возможный указатель - это либо void *, либо указатель на функцию:

std::cout << std::max(sizeof(void*), sizeof(void(*)(void))) << std::endl;
4
mch 18 Апр 2019 в 13:13