Typedef reinterpret_cast - PullRequest
       18

Typedef reinterpret_cast

0 голосов
/ 23 июля 2010

У меня возникли проблемы с определением синтаксиса для typedef reinterpret_cast.Кто-нибудь может помочь?

РЕДАКТИРОВАТЬ :

Что я пытаюсь сделать.Я всегда колеблюсь, потому что люди, кажется, оказываются вовлеченными во все остальное, кроме того, в чем проблема на самом деле, как вы можете видеть из моего последнего поста, который приводит к целой куче ничего.с помощью способа присвоения указателю адреса mem 0.Я использую это в качестве предохранителей и т. Д. Я был уверен, что бросок typedef поможет в этом.Пожалуйста, не советуйте мне использовать NULL.

Спасибо

Ответы [ 3 ]

5 голосов
/ 23 июля 2010

Мне кажется, я наконец понял, что вы хотите, но я все еще не уверен, зачем вы этого хотите, и я подозреваю, что вам это не нужно.Если вы скажете нам, какова ваша конечная цель, мы можем сказать вам, что вам действительно нужно.Тем не менее:

Вы, похоже, знаете, что

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
}

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

1 голос
/ 23 июля 2010

Вы имеете в виду как?

sometype *foobar = 0;

Назначение указателей с нулевым значением - это то, что вы должны сделать вручную в C / C ++.Если вы ищете способ, позволяющий автоматически инициализировать его до нуля, взгляните на классы обтекания указателей, такие как классы autoptr или smartptr.

0 голосов
/ 08 декабря 2011

reinterpret_cast не тип, поэтому вы не можете typedef его. Вы можете обернуть его в template, хотя:

template<typename T> T* improved_null()
{
    return reinterpret_cast<T*>(0);
}

int* foo = improved_null<int>();

Так получилось, что на самом деле reinterpret_cast в этом случае не требуется (возвращаемое значение функции приводится к правильному типу при необходимости):

template<typename T> T* improved_null() { return 0 }

Конечно, если вы хотите улучшить NULL, вы можете рассмотреть nullptr.

...