Безопасный способ переосмыслить необработанную структуру с конкретным смещением и типом? - PullRequest
0 голосов
/ 29 июня 2011
return *reinterpret_cast<UInt32*>((reinterpret_cast<char*>(this) + 2));

Struct упакован в прагму 1 и содержит множество полей uint, char, short ...

Поскольку это UInt32, следует ли сначала переинтерпретировать в неподписанный символ * вместо этого или даже имеет ли это значение?

Кроме того, здесь важна скорость, и я считаю, что reinterpret_cast является самым быстрым из приведений в отличие от static_cast.

РЕДАКТИРОВАТЬ: структура на самом деле состоит из двух однобайтовых полей, за которыми следуетобъединение около 16 других структур, 15 из которых имеют UInt32 в качестве своего первого поля.Я делаю быструю проверку, что это не тот без, и затем делаю reinterpret_cast со смещением в 2 байта.

Ответы [ 4 ]

4 голосов
/ 29 июня 2011

Разве вы не можете просто получить доступ к члену напрямую?Это неопределенное поведение, и оно не будет работать вообще в системах, которые обеспечивают выравнивание слов (что, вероятно, не является проблемой, если вы делаете это, но необходимо упомянуть).

reinterpret_cast не будетбыстрее static_cast, потому что они просто сообщают компилятору, как использовать память во время компиляции.Однако dynamic_cast будет медленнее.

Нет законного способа рассматривать ваш struct + offset как не char тип.

1 голос
/ 29 июня 2011

reinterpret_cast и static_cast должны иметь одинаковое время выполнения - около нуля, если не требуется выполнять числовое преобразование.Вы должны выбрать использование броска не на основе «скорости», а на основе правильности.Если вы говорите о dynamic_cast, у вас может быть причина для аргумента, но и reinterpret_cast, и static_cast обычно приводят (в худшем случае) к регистровой копии (например, из целочисленного регистра в регистр с плавающей запятой).(Если предположить, что ни один пользовательский оператор преобразования не входит в картину, то это вызов функции со всеми сопутствующими вещами)

Безопасного способа сделать то, что вы делаете, не существует.Это нарушает правило строго псевдонимов .Если вы хотите сделать что-то подобное, ваш struct должен быть в какой-то форме union, где вы получите доступ к UInt32 через объединение.

Наконец, как уже упоминалось, этот пример потерпит неудачуна любой платформе с проблемами выравнивания.Это означает, что с x86 у вас все будет хорошо, например с x64 не будет.

0 голосов
/ 30 июня 2011

Поскольку вы говорите, что структура содержит целые числа и шорты, я собираюсь пойти дальше и ответить на вопрос, что это объединение - POD. Если это так, то вы получите 9,5 / 1:

одна специальная гарантия сделана в Для того чтобы упростить использование союзов: Если POD-союз содержит несколько POD-структуры, которые имеют общий начальная последовательность (9.2), и если объект этого типа POD-union содержит одна из POD-структур, это разрешено проверять общее начальная последовательность любой из POD-структур Участники

Итак, если ваша структура выглядит следующим образом:

struct Foo1 { UInt32 a; other stuff; };
struct Foo2 { UInt32 b; other stuff; };
...
struct Foo15 { UInt32 o; other stuff; };
struct Bar { UInt16 p; other stuff; };

// some kind of packing pragma
struct Baz {
    char is_it_Foo;
    char something_else;
    union {
        Foo1 f1;
        Foo2 f2;
        ...
        Foo15 f15;
        Bar b;
    } u; 
};

Тогда вы можете сделать это:

Baz *baz = whatever;
if (baz->is_it_Foo) {
    UInt32 n = baz->u.f1.a;
}

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

0 голосов
/ 29 июня 2011

Вы забыли упомянуть, что вы используете указатель на структуру, а не саму структуру, в любом случае, я считаю ненужным использовать арифметику указателей для определенного поля структуры.Компилятор и сгенерированный код не будут быстрее использовать арифметику указателей и сделают ваш код более сложным, что неоправданнок примеру.

...