Мне кажется, я наконец понял, что вы хотите, но я все еще не уверен, зачем вы этого хотите, и я подозреваю, что вам это не нужно.Если вы скажете нам, какова ваша конечная цель, мы можем сказать вам, что вам действительно нужно.Тем не менее:
Вы, похоже, знаете, что
Foo* p = 0;
определяется как установка p
в качестве нулевого указателя, который на самом деле может или не может быть представлен строкой с нулем-биты в памяти.Похоже, вам нужен способ убедиться, что память, занятая указателем, заполнена нулевыми битами, а не какой-либо битовый шаблон, представляющий нулевой указатель.
Вот два способа сделать это.Самое простое и правильное просто:
Foo* p;
memset(&p, 0, sizeof(p));
Другой, который, кажется, то, о чем вы думали с reinterpret_cast
, заключается в следующем:
Foo* p;
int i = 0;
p = reinterpret_cast<Foo*>(i);
Причина, по которой этоработает и присваивание p
непосредственно к нулю не происходит, потому что только литерал нулей интерпретируются как нулевой указатель при назначении указателям.i
содержит нулевое значение, но не является буквальным нулем.Вышеприведенное неверно, однако, когда указатели и целые числа не имеют одинаковый размер, поэтому лучшим методом может быть:
Foo* p;
char c[sizeof(p)] = {0};
p = reinterpret_cast<Foo*>(c);
Однако это по-прежнему не правильно , потому что этонеопределенное поведение для доступа к результату reinterpret_cast
, когда вы врете о реальном типе переменной, которую вы бросили.c
на самом деле не Foo*
выше, так что это неопределенное поведение.Таким образом, вы должны использовать memset
для достижения этой цели.
Причина, по которой вы, похоже, хотели typedef
, заключается в том, что вы можете иметь тип указателя, которому автоматически присваивается значение 0 при создании.К сожалению, это невозможно.typedef
может указывать только тип, но не начальное значение.Помимо создания собственного класса смарт-указателя для этого, лучшее, что вы могли бы сделать, это заключить вызов в memset
в удобную функцию, например,
template <typename T> T* zeroPointer() {
T* p;
memset(&p, 0, sizeof(p));
return p;
}
Foo* p = zeroPointer<Foo>();
Теперь, даже учитывая все это,это все еще не может дать вам то, что вы хотите во всех случаях.Как отметил в своих комментариях GMan, не гарантируется, что указатели представлены числами на всех платформах, поэтому значение p
может не быть числовым нулем после этого и может не соответствовать address 0 onсистема, даже если это все нули.Данная система может даже не иметь такого понятия, как «адрес 0».Например, в конкретной системе указатель может быть представлен структурой, содержащей адрес сегмента и смещение.
Наконец, имейте в виду, что вам придется приложить дополнительные усилия для test для этого значения.Например:
Foo* p = zeroPointer<Foo>();
if (p == 0) {
// Not reached if NULL is not all-zero bits, since the literal 0 in the
// comparison is interpreted as a null pointer constant
}
По сути, вам придется проверять каждый бит отдельно.Единственный способ сделать это без вызова неопределенного поведения - это что-то вроде этого:
template <typename T> bool isZero(T& p)
{
char c[sizeof(p)];
memcpy(&c, &p, sizeof(p));
for (int i = 0; i < sizeof(p); ++i) {
if (c[i] != 0) return false;
}
return true;
}
Foo* p = zeroPointer<Foo>();
if (isZero(p)) {
// Always reached
}
Это все довольно громоздко, потому что вы работаете против языка здесь.Язык пытается быть полезным, предоставляя портативный метод установки нулевых указателей, но вы хотите отказаться от этого и по какой-то причине создать свой собственный указатель с нулевыми битами.Вот почему я убежден, что все, что вы в конечном итоге хотите сделать, может быть сделано другим способом, который не включает борьбу с языком, на котором вы программируете.