строка создает символ с именем *Pile
, который задает значение адреса в PileInts
Нет.Он создает указатель на символ char*
с именем Pile
, который указывает на самый младший байт в первом int
в массиве int
-
Могу ли я получить более глубокое объяснение?
Код дает указатель, который можно использовать для доступа к отдельным байтам первого int
в массиве, а оттуда к отдельным байтам следующих смежных int
до концамассив.
Это возможно, потому что когда имя массива используется в выражении, оно «разлагается» на указатель на первый элемент этого массива.Делая PileInts
, при использовании в массиве, эквивалентно типу int*
.
Преобразование из int*
в char*
допустимо, но подозрительно C. Некоторые вещи, о которых следует знать:
Прежде всего, uint8_t*
следует использовать всякий раз, когда кто-то пытается получить доступ к необработанным значениям данных.Тип char
очень проблематичен, поскольку имеет подпись, определяемую реализацией - его не следует использовать ни для чего другого, кроме символов и строк. Является ли символ подписанным или неподписанным по умолчанию?
Этот указатель будет указывать на самый низкий адрес первого int
.Каким байтам это соответствует, зависит от процессора, а именно от endianess процессора.Использование операторов побитового сдвига вместо указателей приведет к удалению этой зависимости процессора, поэтому в зависимости от того, что вы хотите сделать с этим указателем, он может или не может быть подходящим инструментом для этой задачи.
Что касается самого преобразования указателя, то оно хорошо в соответствии с C17 6.3.2.3/7:
Указатель на тип объекта может быть преобразован в указатель на другой тип объекта.Если результирующий указатель неправильно выровнен для ссылочного типа, поведение не определено.В противном случае при обратном преобразовании результат сравнивается равным исходному указателю.
Это означает, что что-то вроде (int*) ((char*)PileInts + 1)
будет неопределенной ошибкой в поведении, потому что int*
будет смещен.
Тот же параграф в стандарте продолжается:
Когда указатель на объект преобразуется в указатель на тип символа, результат указывает на младший адресуемый байт объекта.Последовательные приращения результата, вплоть до размера объекта, дают указатели на оставшиеся байты объекта.
Это правило, позволяющее нам перебирать любой тип данных с помощью символьного указателя(или предпочтительно эквивалент uint8_t*
).То же самое не верно для любого другого типа указателя, мы могли бы, например, не использовать short*
, чтобы сделать то же самое, думая, что мы перебираем 16-битные слова.
Существует также другое правило, запрещающее нам использовать любой другой тип указателя, а именно правило, регулирующее внутреннюю систему типов компилятора и то, как разные указатели могут быть псевдонимами друг друга.Неформально известный как строгое правило псевдонимов .Это правило также имеет исключение только для типов символов.То есть мы не можем сделать это:
int PileInts[1024];
char *Pile = (char *)PileInts;
short* sptr = (short*)Pile; // very questionable cast but not a bug yet
printf("%h", *sptr); // bug, data is accessed as wrong type, strict aliasing violation