2012-03-19 2 views
4

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

предупреждение: разыменования типа каламбурил указатель будет нарушать правила строгого сглаживания [-Wstrict-алиасы]

Строка моя собственная строка, которая является POD. Этот код вызывается из C. S может быть int. Строка в значительной степени struct String { RealString*s; }, но шаблонные и вспомогательные функции. Я делаю статическое утверждение, чтобы убедиться, что String является модулем, составляет 4 байта, а int - 4 байта. Я также написал утверждение, которое проверяет, есть ли все указатели> = NotAPtr. Его в моей новой перегрузке/malloc. Я могу поставить это утверждение в String, если вы предложите

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

void func(String s) { 
    auto v=*(unsigned int*)&s; 
    myassert(v); 
    if(v < NotAPtr) { 
     //v is an int 
    } 
    else{ 
     //v is a ptr 
    } 
} 
+1

«Как быстро я могу ездить без получения ускоренного билета?» Microsoft сделала что-то подобное с помощью «MAKEINTRESOURCE», но они тоже пишут компилятор и могут добавить расширение. Обыкновенных смертных не может. И в C++ они могли бы добавить перегрузку. –

+2

Здесь вы на скользком склоне. У вас действительно есть веская причина не создавать отдельные функции func_i и func_s? –

+1

@PerJohansson: Я сделал это в начале проекта. Теперь эта причина больше не существует. Поэтому я сделал 2 функции. +1 –

ответ

-1

Безопасный способ обработки переменной как двух разных типов - превратить ее в союз. Одной частью объединения может быть ваш указатель, а другая часть - целое число.

struct String 
{ 
    union 
    { 
     RealString*s; 
     int i; 
    }; 
}; 
+1

Технический союз может не работать для типа punning, и если хранилище '' '' '' 'from' i' не определено (оно может быть всегда 0, например). Однако в этом случае существует строгое нарушение псевдонимов из-за странного приведения - не из-за какого-либо «реального» нарушения, поэтому можно просто отбрасывать из указателя в int. –

+1

-1 для указания неопределенного поведения. –

+1

@BenVoigt: На самом деле, чтение из члена 'union', кроме последнего написанного, является * неуказанным * поведением, а не * undefined *. – jamesdlin

1

Если вы не можете изменить код для 2 функций в соответствии с предложением, почему нет (требует C99 компилятора, как использует uintptr_t - для старшего MSVC вам нужно определить его самостоятельно, 2008/2010 должен быть в порядке):

void f(RealString *s) { 
    uintptr_t int = reinterpret_cast<uintptr_t>(s); 
    assert(int); 
} 
4

memcpy полностью поддерживается. Так наносит штраф char* (например, вы можете использовать std::copy).

+0

Я не уверен в C++, но, конечно, в C99 функция memcpy гарантирована только для преобразования типов в случаях, когда операнд назначения имеет объявленный тип. Спецификации сталкиваются с множеством проблем, чтобы предотвратить «memcpy» от безопасного использования для копирования объекта одного типа на хранилище без объявленного типа с целью доступа к нему как к другому типу. – supercat

+0

@supercat: Я вижу, что 'string.h' имеет следующее правило, которое поэтому применяется к' memcpy' - "Если явно не указано иначе в описании конкретной функции в этом подпункте, аргументы указателя на такой вызов все равно должны иметь действительные значения, как описано в 7.1.4. " Что именно в 7.1.4 вы считаете проблемой здесь? И как бы вы получили «хранилище без объявленного типа» в первую очередь? И почему это имеет значение для описанного сценария, который является «int i; memcpy (& i, & s, sizeof i); '? –

+0

В C99 (и я не думаю, что это изменилось в C11), учитывая 'int x = 1234; long * p = malloc (sizeof (long)); * p = 5678; memcpy (p, & x, sizeof x;); 'попытка прочитать' * p' как 'long' будет вызывать Undefined Behavior, даже если' int' и 'long' имеют одинаковое представление, так как' memcpy' установит значение Effective Тип '* p' в' int'. – supercat

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