Если «строгое правило псевдонимов» (N1570 6.5p7) интерпретируется просто как указание обстоятельств, при которых вещи могут иметь псевдонимы (что может показаться тем, что предполагали авторы, учитывая сноску 88, в которой говорится «Намерение этого списка»состоит в том, чтобы указать те обстоятельства, при которых объект может быть или не быть псевдонимом ") код, подобный вашему, не должен создавать проблем при условии, что во всех контекстах, когда к объекту обращаются с использованием l-значений двух разных типов, одно из задействованных l-значений является явно свежим производнымот другого.
Единственный способ, которым 6.5p7 может иметь какой-либо смысл, - это если операции с объектами, которые недавно были визуально получены из других объектов, распознаются как операции с оригиналами.Однако вопрос о том, когда признавать такой вывод, остается вопросом качества реализации, и считается, что рынок сможет лучше судить, чем Комитет, о том, что необходимо для того, чтобы что-то было «качественным» осуществлением, подходящим для некоторого конкретного случая.цель.
Если цель состоит в том, чтобы написать код, который будет работать на реализациях, настроенных на выполнение четкого замысла сноски 88, то следует быть уверенным, что объекты не имеют псевдонимов.Отстаивание этого требования может потребовать, чтобы один гарантировал, что компилятор может видеть, что указатели связаны друг с другом или что каждый из них был недавно получен из общего объекта в точке использования.Учитывая, например,
thing1 *p1 = unionArray[i].member1;
int v1 = p1->x;
thing2 *p2 = unionArray[j].member2;
p2->x = 31;
thing1 *p3 = unionArray[i].member1;
int v2 = p3->x;
каждый указатель будет использоваться в контексте, где он был недавно получен из unionArray
, и, таким образом, не будет псевдонимов, даже если i==j
.Компилятор, такой как «icc», не будет иметь проблем с таким кодом, даже с включенным -fstrict-aliasing
, но, поскольку и gcc, и clang предъявляют требования 6.5p7 к программистам даже в случаях, не связанных с псевдонимами, они не будут обрабатывать его правильно.
Обратите внимание, что если бы код был:
thing1 *p1 = unionArray[i].member1;
int v1 = p1->x;
thing2 *p2 = unionArray[j].member2;
p2->x = 31;
int v2 = p1->x;
, то при втором использовании p1
будет псевдоним p2
в случаях, когда i==j
, поскольку p2
будет обращаться к хранилищу, связанномус p1
, через средства, не включающие p1
, между временем p1
и последним временем его использования (таким образом, псевдоним p1
).
Согласно авторам Стандарта,Дух C включает в себя принципы «Доверяй программисту» и «Не мешай программисту делать то, что ему нужно».Если нет особой необходимости справляться с ограничениями реализации, которая не особенно хорошо подходит для того, что вы делаете, следует ориентироваться на реализации, которые поддерживают Дух C способом, соответствующим его целям.Диалект -fstrict-aliasing
, обработанный icc, или диалект -fno-strict-aliasing
, обработанный icc, gcc и clang, должны подходить для ваших целей.-fstrict-aliasing
диалекты gcc и clang должны быть признаны просто непригодными для ваших целей и не стоящими нацеливания.