Зарезервированные адреса указателей (используются как особые случаи) - PullRequest
1 голос
/ 14 марта 2012

Безопасно ли делать следующее?

MyClass* p = WantItInCase1();
if (p == NULL)
    p = 0x1;
else
   p = WantItInCase2();
if (p == NULL)
   p = 0x2;
...
CheckCases (p);  // we check '0x1' and '0x2' cases and otherwise process 'p' as normal object

У меня есть ситуация, когда MyClass объекты не могут обработать все варианты, необходимые в CheckCases(). Таким образом, чтобы избежать дополнительного параметра, возможно ли использовать этот подход? По крайней мере, мне нужен диапазон адресов, которые нельзя использовать для new выделения.

--- Обновление ---

Принимая во внимание ответы, я решил сделать несколько «хитрый» подход:

// somewhere in global definitions:
const MyClass* P_CASE_1 = (MyClass*) new int;
const MyClass* P_CASE_2 = (MyClass*) new int;
...
// previous code piece:
MyClass* p = WantItInCase1();
if (p == NULL)
    p = P_CASE_1;

Это было бы безопасно для памяти, и не опасно пропускать 4 байта для каждого P_CASE_#.

Ответы [ 4 ]

2 голосов
/ 14 марта 2012

С GCC этот вид назначения "по умолчанию" запрещен.Вам придется форсировать компиляцию с помощью флага -fpermissive.

Я думаю, что это не "хорошо".Я предпочитаю такой подход:

MyClass* p = WantItInCase1();
int flag;
if (p == NULL)
    flag = 0x1;
else
   p = WantItInCase2();
if (p == NULL)
   flag = 0x2;
...
CheckCases (flag);

Конечно, больше "памяти" используется, но сегодня, что такое 4 байта?

Итак, чтобы ответить на ваш вопрос, это назначениеочень обескуражены ... Но ваша программа может работать ...

Если вы попытаетесь прочитать p (в вашем методе checkclass), вы напишите что-то вроде:

if(p == 0x1) ...

Такого родаof line сгенерирует предупреждение (с GCC), потому что вы сравниваете указатель на целое число, поэтому: один флаг предупреждения + -fpermissive = не делайте этого!

0 голосов
/ 14 марта 2012

Это не только неопределенное поведение, но и очень специфичное для платформы, так как этого действительно следует избегать, что можно сделать с помощью пользовательского указателя с подсчетом ссылок (где для ваших особых случаев используется отрицательная ссылка) или вспомогательной переменной или даже некоторые причудливые do{}while(0) конструкции.

Если вы действительно хотите пометить указатели, первая страница (64 КБ) под окнами зарезервирована и никогда не будет размещена в пользовательском пространстве или ядре. То же самое касается MSB адреса, который зарезервирован для пространства ядра. Однако вам нужно будет выполнить кастинг, для этого uintptr_t подойдет хорошо.

0 голосов
/ 14 марта 2012

Это зависит от реализации.На компиляторах Microsoft, ориентированных на Windows, это будет работать.Макрос MAKEINTRESOURCE делает то же самое.

0 голосов
/ 14 марта 2012

Это зависит от ОС: -)

Чтобы было ясно: в 32-битной Windows 32 последние гигабайты адресного пространства всегда резервируются для ядра, поэтому вы можете использовать его адреса для своего использования.Обычно это последние 2 ГБ адресного пространства, но с помощью переключателя / 3GB вы можете изменить его.Подобный трюк используется в ядре для некоторых структур данных.

Я бы никогда этого не сделал: -)

Я добавлю, что, вероятно, 0x1, 0x2, 0x3 довольно безопасны,Так как адреса, предоставляемые вам операционной системой, обычно выровнены не менее чем на 32 бита, 0x0 определен для специальных целей, поэтому следующие три байта не будут выделяться в блоке памяти.Ааа ... Слишком сложно объяснить.Допустим, среда выполнения C забирает память у ОС, а эта «стандартная» ОС никогда не отдаст память в диапазоне 0x0-0x3.

...