Существует более элегантный способ решения этой проблемы, если вы используете backbonejs:
initialize: function(){ this.addListener_openWidget(); } addListener_openWidget: function(){ this.listenToOnce( this, 'openWidgetView', function(e){this.openWidget(e)} ); }, events: { 'click #openWidgetLink' : function(e){this.trigger('openWidgetView',e)}, 'click #closeWidgetLink' : 'closeWidget' }, openWidget: function( e ){ //Do your stuff }, closeWidget: function(){ this.addListener_openWidget(); }
Типичная ситуация Вы встречаетесь со строгими проблемами искажения, при накладывании структуры (как устройство/сетевое сообщение) на буфер размера слова системы (как указатель на 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 доступу:
Тип, каламбурящий через броски указателя (в противоположность использованию объединения), является главным примером повреждения строгого искажения.
Строгое искажение не позволяет различные типы указателей тем же данным.
Эта статья должна помочь Вам понять проблему в полных деталях.
Лучшее объяснение, которое я нашел, Mike Acton, Понимающее Строгое Искажение . Это сфокусировалось немного на разработке PS3, но это - в основном просто GCC.
От статьи:
"Строгое искажение является предположением, сделанным C (или C++) компилятор, то разыменование, которое указатели на объекты различных типов никогда не будут отсылать к той же ячейке памяти (т.е. искажать друг друга.)"
Так в основном, если Вы имеете int*
указывающий на некоторую память, содержащую int
и затем Вы указываете float*
на ту память и используете ее в качестве float
, Вы нарушаете правило. Если Ваш код не будет уважать это, то оптимизатор компилятора, скорее всего, повредит Ваш код.
исключение из правила char*
, которому позволяют указать на любой тип.