Типичная ситуация Вы встречаетесь со строгими проблемами искажения, при накладывании структуры (как устройство/сетевое сообщение) на буфер размера слова системы (как указатель на uint32_t
с или uint16_t
с. Когда Вы накладываете структуру на такой буфер, или буфер на такую структуру через указатель, бросая Вас может легко нарушить строгие правила искажения.
Так в этом виде установки, если бы я хочу отправить сообщение во что-то, у меня должно было бы быть два несовместимых указателя, указывающие на тот же блок памяти. Я мог бы тогда наивно кодировать что-то вроде этого:
typedef struct Msg
{
unsigned int a;
unsigned int b;
} Msg;
void SendWord(uint32_t);
int main(void)
{
// Get a 32-bit buffer from the system
uint32_t* buff = malloc(sizeof(Msg));
// Alias that buffer through message
Msg* msg = (Msg*)(buff);
// Send a bunch of messages
for (int i =0; i < 10; ++i)
{
msg->a = i;
msg->b = i+1;
SendWord(buff[0]);
SendWord(buff[1]);
}
}
строгое правило искажения делает эту установку недопустимой: разыменование указателя, который искажает объект, который не имеет совместимый тип или один из других типов, позволенных к 2011 C 6,5 абзацев 7 1 глоток>, является неопределенным поведением. К сожалению, можно все еще кодировать этот путь, , возможно получают некоторые предупреждения, имеют его прекрасная компиляция, только для имения странного неожиданного поведения, когда Вы выполняете код.
(GCC кажется несколько непоследовательным в своей способности дать предупреждения искажения, иногда давая нам дружественное предупреждение и иногда нет.)
Для наблюдения, почему это поведение не определено мы должны думать о том, что строгое правило искажения покупает компилятор. В основном, с этим правилом, это не должно думать о вставке инструкций обновить содержание buff
каждое выполнение цикла. Вместо этого при оптимизации, с некоторыми раздражающе добровольными предположениями об искажении, это может опустить те инструкции, загрузка buff[0]
и buff[1
] в ЦП регистрируется однажды, цикл выполняется, и ускорьте тело цикла. Прежде чем строгое искажение было представлено, компилятор должен был жить в состоянии паранойи, которую содержание buff
могло изменить в любое время отовсюду кем-либо. Таким образом для получения дополнительного края производительности, и принимающий большинство людей не делают указателей игры слов типа, строгое правило искажения было представлено.
Имеют в виду, если Вы думаете, что пример изобретен, это могло бы даже произойти при передаче буфера другой функции, делающей посылание за Вами если вместо этого Вы имеете.
void SendMessage(uint32_t* buff, size_t size32)
{
for (int i = 0; i < size32; ++i)
{
SendWord(buff[i]);
}
}
И переписал наш более ранний цикл для использования в своих интересах этой удобной функции
for (int i = 0; i < 10; ++i)
{
msg->a = i;
msg->b = i+1;
SendMessage(buff, 2);
}
, компилятор может или не может быть в состоянии или достаточно умный, чтобы попытаться встроить SendMessage, и это может или не может решить загрузить или не загрузить любителя снова. Если SendMessage
часть другого API, это компилируется отдельно, это, вероятно, имеет инструкции загрузить содержание любителя. С другой стороны возможно, Вы находитесь в C++, и это - некоторый шаблонный заголовок только реализация, что компилятор думает, что это может встроить. Или возможно это - просто что-то, что Вы записали в своем.c файле для Вашего собственного удобства. Так или иначе неопределенное поведение могло бы все еще последовать. Даже когда мы знаем часть из того, что происходит под капотом, это - все еще нарушение правила, таким образом, никакое четко определенное поведение не гарантируется. Таким образом, только путем обертывания в функции, которая берет наше слово, которому не обязательно помогает разграниченный буфер.
Поэтому, как я обхожу это?
Использование объединение. Большинство компиляторов поддерживает это, не жалуясь на строгое искажение. Это позволяется в C99 и явно позволяется в C11.
union {
Msg msg;
unsigned int asBuffer[sizeof(Msg)/sizeof(unsigned int)];
};
можно отключить строгое искажение в компиляторе ( f [нет-] строгое искажение в gcc))
, можно использовать char*
для искажения вместо слова системы. Правила позволяют исключение для [1 112] (включая [1 113] и unsigned char
). Всегда предполагается что char*
псевдонимы другие типы. Однако это не будет работать другой путь: нет никакого предположения, что Ваша структура искажает буфер символов.
Новичок остерегается
, Это - только одно потенциальное минное поле при накладывании двух типов друг на друга. Необходимо также изучить [приблизительно 1 118] порядок байтов , выравнивание слов , и как заниматься проблемами выравнивания до [1 120] структуры упаковки правильно.
1 глоток> типы, что 2011 C 6.5 7 позволяет lvalue доступу:
Я сталкиваюсь с этой строкой кода:
iframe.setAttribute("src", "javascript:false");
также. Я хотел удалить javascript:URL
.
Найденный этим примечанием от веб-гипертекстовой Технологической Рабочей группы Приложения [Обновленный 2 октября 2019]
иначе шаги для iframe или элементов кадра следующие:
, Если элемент не имеет никакого атрибута src, указанного, или его значение является пустой строкой, позвольте URL быть URL "about:blank".