Следующий код нарушает строгий псевдоним? - PullRequest
0 голосов
/ 19 января 2019

Нарушает ли следующий код строгий псевдоним?

int a = 0;
*((int *)((char *)&a)) = 1;

Почему бы и нет? , потому что мы в конечном итоге разыменовываем указатель на int a, используя int *, что является допустимым

Почему да? , потому что мы приводим char * к int * и разыменовываем его (int *), что выглядит как строгое нарушение псевдонимов

Ответы [ 3 ]

0 голосов
/ 19 января 2019

Нет, это не нарушение.

, потому что мы разыгрываем char * в int *

Вам не хватает той части, которую char *, которую вы упомянули, на самом деле int *. Таким образом, наконец, доступ к типу int осуществляется через указатель на int - это совершенно правильно.

0 голосов
/ 19 января 2019

Строгие правила псевдонимов не заботятся о промежуточных приведениях.Они заботятся только о типе указателя, который в конечном итоге используется для доступа к объекту, и об исходном типе самого объекта (технически это «эффективный тип», но это сейчас не важно).

В вашем примере кода, вы берете адрес int.Результат имеет тип int *.Вы приводите этот указатель к char *, вы снова приводите его к int *, и только тогда вы разыменовываете его.Тип указателя, используемого при доступе, - int *, а тип объекта, на который указывает объект, - int, поэтому у правил строгого алиасинга нет проблем.

Вы правы, что правила строгого алиасингаасимметричный относительно char, но это имеет значение только тогда, когда либо тип самого объекта равен char, либо тип указателя, используемого при доступе, равен char:

char x[sizeof(int)] = { 0 };
*(int *)x = 1;  // undefined behavior

int y = 1234;
*(char *)y = 0; // valid; value of y becomes unspecified

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

0 голосов
/ 19 января 2019

Этот код действителен.Разрешается преобразование между двумя типами указателей объектов и обратно при условии, что нет проблем с выравниванием, и преобразованию в char * явно разрешен доступ к представлению объектов (т. Е. Чтение отдельных байтов).

Раздел 6.3.2.3p7 стандарта C гласит:

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

Поскольку вы преобразуете от int * до char *, а затем обратно к int *, здесь нет строгих нарушений алиасинга.

...