2010-07-21 2 views
10

В соответствии со стандартом C++, reinterpret_cast указателя T* на указатель другого типа Q*can change or not change the pointer value в зависимости от реализации.Любой реальный пример reinterpret_cast, изменяющего значение указателя?

Мне очень интересно - это какой-нибудь реальный пример реализации на C++, в котором литье указателя на какой-либо другой тип указателя с reinterpret_cast изменяет указатель? Что и почему там изменилось?

+0

Вы имеете в виду, что «изменяет значение» указывает указатель? – akira

+0

@akira: no, изменяет значение самого указателя – sharptooth

+0

вы имеете в виду: 'T * t = 0x13; Q * q = 0x42; t = reintrepret_cast (q); 'дает' t! = 0x42'? – akira

ответ

6

Обратите внимание, что когда стандарт утверждает, что он может или не может что-то сделать, это не означает, что существует какая-либо текущая реализация, которая имеет такое поведение, только то, что они могли.

Самое близкое, что я могу придумать, это архитектура, в которой требуется аппаратное обеспечение выравнивания по типу, и реализация, которая при необходимости решила корректировать выравнивание. Что-то вроде:

aligned8 var; 
aligned1 *p = reinterpret_cast<aligned1*>(&var); 
aligned1 *q = p + 1; // assuming aligned 1 size is not multiple of 8 
aligned8 *a = reinterpret_cast<aligned8*>(q); // [1] 

Там может быть требование, чтобы для a быть действительным указателем он должен адресовать позицию памяти кратно 8, в то время как аргумент q с меньшими требованиями выравнивания может указывать на любой адрес памяти.

2
class A1 { int a1; }; 
class A2 { int a2; }; 

class B: public A1, public A2 { }; 

#define DBG(val) cout << #val << ": " << val << endl 

// test code 
B b; 
DBG(&b);           // prints 0x42 

void *p_blank = &b; 
DBG(p_blank);          // prints 0x42 
A2 *p_a2 = &b; 
DBG(p_a2);           // prints 0x46 
void *p_reinterpreted = reinterpret_cast<A2*>(&b); 
DBG(p_reinterpreted);        // prints 0x42 
A2 *p_reinterpreted2 = reinterpret_cast<A2*>(&b); 
DBG(p_reinterpreted2);        // prints 0x42 

A2 *p_a2 = &b средства дать мне указатель на объект А2 внутри объекта B. reinterpret_cast<A2*>(&b) означает дайте мне указатель на b и обработайте его как указатель A2. Результат этого reinterpret_cast имеет тип «указатель на A2», поэтому он не выдает предупреждения при назначении переменной void * (или переменной A2 *).

+0

'A2 * p_a2 = & b;' меня удивляет ... – akira

+5

В вашем примере 'reinterpret_cast' вообще не изменяет значение ... вы ушли, я боюсь. –

+0

В 'A2 * p_a2 = & b;' вы используете неявное преобразование, эквивалентное 'static_cast', а не' reinterpret_cast'. – sharptooth

0

Reinterpret_cast никогда не будет возвращать другой адрес - требуется скопировать точный адрес.

В случаях множественного наследования, например, Дэвид Родригес сказал, что, взяв адрес одной из баз, может вернуть адрес, который имеет смещение по адресу первой базы. Reinterpret_cast вернет этот адрес смещения, но если вы будете рассматривать его как адрес upcast, произойдет ад.

Для повышения эффективности static_cast может возвращать другой адрес, отличный от указанного. Если адрес, который у вас есть, является одним из оснований, и этот адрес находится на смещении к первому базовому адресу, static_cast вернет действительный адрес для объекта с повышением уровня, который равен адресу первой базы и, следовательно, не равен к указателю.

Чтобы сделать это коротко: reinterpret_cast дает вам тот же адрес, всегда. Static_cast и dynamic_cast могут возвращать другой адрес, например. в некоторых случаях с множественным наследованием.

Разница между static_cast и dynamic_cast заключается в том, что static_cast не проверяет, является ли указатель, который вы ему указываете, правильным объектом для трансляции, поэтому обязательно перед этим вызовите его.

+1

Заявление с требованием «требуется» должно быть скопировано с источником. Все, что я вижу, это то, что вы можете конвертировать в указатель с менее строго выровненным типом *, а затем обратно * и «Результат любого другого такого преобразования указателя не указан». (5.2.10/7) – Potatoswatter

+1

Ум, я полностью упустил проблемы с выравниванием, я вижу, как это изменит адрес. Спасибо за исправление. – Alex

1

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

Наиболее вероятным эффектом является усечение, поскольку тип указателя адресата не имеет битов для указания части индекса.C++ 11 дает кивок в этом направлении, позволяя любым типам указателей быть reinterpret_cast ed, если они имеют одинаковые требования к выравниванию. Биты, «обнуленные» строгим выравниванием, не могут существовать.

Указатель объекта может быть явно преобразован в указатель объекта другого типа. Когда prvalue v типа «указатель на T1» равен , преобразованный в тип «указатель на cv T2», результат равен static_cast<cv T2*>(static_cast<cv void*>(v)), если оба T1 и T2 являются стандартными макетами (3.9) , а требования к выравниванию T2 являются не более строгие, чем те из T1, или если любой тип недействителен. Преобразование prvalue типа «указатель на T1» на тип «указатель на T2» (где T1 и T2 - это типы объектов и где требования к выравниванию T2 не равны , более строгие, чем у T1) и обратно к исходному типу дает исходное значение указателя . Результат любого другого такого указателя преобразование не определено.

1

Я не думаю, что вопрос имеет смысл для C++ и C-указателей. Из this answer цитирует только один из примеров:

серия

Затмения MV от общих данных имеет три архитектурно поддерживаемый указатель форматов (Word, байтовые и битовые указатели), два из которых используется компилятором C: байтовые указатели для char* и void* и указателей слова для всего остального

Это наводит на мысль в reinterpret_cast<Word_Aligned_Type*>(char*) может потерять свой смысл которого символ/байты в слове был быть направлен на, что делает операцию необратимой.

Смежные вопросы