насколько я знаю, например, целые числа помещаются в память в целых числах, кратных их размеру. Могу ли я получить доступ к набору байтов, начиная с числа, кратного sizeof(int), через указатель в виде int? Код ниже, кажется, работает, создавая
Размер int: 4 собственный порядок байтов: LSB 0 127 0 0 0 0 0 0 0 0 0 0
Это гарантировано или нет? Спасибо.
#include <string.h>
#include <iostream>
#include <bit>
using namespace std;
int main()
{
cerr<<"Size of int: "<<sizeof(int)<<endl;
if (std::endian::native == std::endian::little) cerr<<"native byte order: LSB"<<endl;
else cerr<<"native byte order: MSB"<<endl;
const int N = 3;
int array_int[N];
memset(array_int,0,sizeof(int)*N);
std::byte *array_byte = (std::byte*)array_int;
int *ptr = (int*)(array_byte+1);
*ptr = 127;
for(int i=0; i<N*sizeof(int); ++i) cerr<<(int)(array_byte[i])<<" ";
cerr<<endl;
return 0;
}
Приведенный выше пример компилируется и запускается, как и ожидалось, наивно.
Всякий раз, когда вы выполняете явное преобразование в стиле C (приведение, которое вы делаете для array_byte), это следует воспринимать как признак того, что вы, вероятно, делаете что-то неправильно. Он может по-прежнему работать и поддерживаться вашей системой, но где-то еще могут быть другие проблемы (возможно, плохой дизайн?).
Это неопределенное поведение для доступа к невыровненному объекту. Это не означает, что он должен сломаться: соответствующая реализация может последовательно работать так, как вы ожидаете.
Используйте memcpy, чтобы скопировать интересующие вас байты в переменную int переносимым способом. Компилятор будет исключать вызовы memcpy, когда это возможно.





std::byte *array_byte = (std::byte*)array_int; int *ptr = (int*)(array_byte+1); *ptr = 127;
Это неопределенное поведение.
Проблема в том, что вы обращаетесь к объекту типа int, но ptr не указывает на такой объект.
Невозможно, чтобы int существовал по адресу, где он был бы смещен (см. [basic.align] стр. 1):
Тип объекта накладывает требование выравнивания на каждый объект этого типа; [...]
Даже если бы объект int существовал по адресу array_byte + 1, возможно, он вам понадобится, потому что «прогулка» вверх по представлению объекта std::launder не дает вам указатель на array_byte по этому адресу; он дает вам только указатель на байты представления объекта.
Код ниже, кажется, работает, [...]
Неопределённое поведение часто создаёт видимость работоспособности, но на самом деле оно не работает. Это может «сработать», потому что вы компилируете для x86_64, где возможны невыровненные чтения. В другой архитектуре ЦП может вызвать исключение, как и при делении на ноль. С другим компилятором ваш код можно просто превратить в тарабарщину или полностью оптимизировать.
Вы можете: это называется чтением/записью без выравнивания, но только если ваш целевой компьютер поддерживает это, а не все. См. здесь: stackoverflow.com/q/64501099/159145 и здесь: stackoverflow.com/q/28996867/159145