Почему указатель не может соответствовать переменной другого типа, даже если sizeof одинаков? - PullRequest
0 голосов
/ 08 апреля 2019

Почему размер любого указателя составляет 4 или 8 байт, но он не может соответствовать какой-либо другой переменной?Я получаю сообщение об ошибке при попытке присвоить двойному указателю значение int-указателя.

int          *int_ptr{nullptr};
float        *float_ptr{nullptr};
double       *double_ptr{nullptr};
long double  *long_double_ptr{nullptr};
string       *string_ptr{nullptr};
vector<int>   *vector_ptr{nullptr};

cout << "sizeof int pointer is " << sizeof int_ptr;    //8 or 4
cout << "sizeof float pointer is " << sizeof float_ptr;    //8 or 4
cout << "sizeof double pointer is " << sizeof double_ptr;    //8 or 4
cout << "sizeof double double pointer is " << sizeof long_double_ptr;    //8 or 4
cout << "sizeof string pointer is " << sizeof string_ptr;    //8 or 4
cout << "sizeof vector int pointer is " << sizeof vector_ptr;  //8 or 4

double double_num{1020.7};
double_ptr = &int_ptr;      //cannot convert ‘int**’ to ‘double*’ in assignment

Ответы [ 3 ]

3 голосов
/ 08 апреля 2019

C ++ - статически типизированный язык. Язык обеспечивает безопасность типов и защищает вас от ошибок, отклоняя произвольные преобразования между несвязанными типами. Значение типа не полностью описывается одним только размером.

Если адрес содержит объект типа int*, то int** может указывать на этот объект. Учитывая, что адрес содержит объект типа int*, он также не может содержать объект типа double, поэтому не существует осмысленного способа преобразования одного из этих указателей в другой.

0 голосов
/ 08 апреля 2019

Этот код недопустим, поскольку не существует «неявного преобразования» для сопоставления с &int_ptr в double_ptr, где «неявное преобразование» определяется как нечто:

Выполняется всякий раз, когда выражение некоторого типа T1 используется в контексте, которое не принимает этот тип, но принимает некоторый другой тип T2;в частности:

  • , когда выражение используется в качестве аргумента при вызове функции, объявленной с T2 в качестве параметра;
  • , когда выражение используется в качестве операнда соператор, который ожидает T2;при инициализации нового объекта типа T2, включая оператор return в функции, возвращающей T2;
  • , когда выражение используется в операторе switch (T2 является целочисленным типом);
  • когда выражение используется в операторе if или в цикле (T2 - это bool).Программа корректно формируется (компилируется), только если существует одна однозначная неявная последовательность преобразования из T1 в T2.

Я изначально предложил вы используетеreinterpret_cast, но это также не сработает, так как использование результата reinterpret_cast между типами допустимо только в том случае, если типы различаются только в зависимости от того, подписаны ли они, а тип приводится к - это byte*, char* или unsigned char*, или типы являются «похожими», что определяется как:

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

Как вы не видите ни одной из этих ситуацийприменяется к желающим разыграть с адреса int* int_ptr до double* double_ptr.Мне сложно предсказать ваш вариант использования для этого типа приведения на строго типизированном языке , но, возможно, void* - это то, что вы ищете?Он может указывать на или действительный int**, в этом случае вы можете инициализировать его следующим образом: const void* ptr = reinterpret_cast<void*>(&int_ptr) или действительный double*, в этом случае вы инициализируете его следующим образом: const void* ptr = reinterpret_cast<void*>(double_ptr),Конечно, для использования ptr вам понадобится переменная, сообщающая вам, какой тип она содержит, например:

if(is_int) {
    // recover int** (reinterpret_cast<const int* const*>(ptr)) and operate on it
} else {
    // recover double* (reinterpret_cast<const double*>(ptr)) and operate on it
}

Live Example

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

0 голосов
/ 08 апреля 2019

Указатели являются адресами. Допустим, у вас есть два адреса:

  1. 53 Главный проспект
  2. 85 WrongTurn Road

Первый - это адрес маленького дома с 2 спальнями. Второе - это адрес особняка, 23 спальни, 10 ванных комнат и т.д ...

Вы не можете ожидать, что все люди, живущие в особняке, переместятся в небольшой дом? но угадайте что? в почтовом отделении их размеры коробки такие же! Вот как они работают. Они просто говорят вам, где найти вашу переменную. Это не контейнеры

...