Стандарт позволяет нам приводить указатели на тип объекта друг к другу, если они правильно выровнены. 6.3.2.3(p7)
Указатель на тип объекта может быть преобразован в указатель на
другой тип объекта. Если результирующий указатель не правильно
align68) для ссылочного типа поведение не определено.
Стандарт позволяет нам копировать представление объекта в char[sizeof(the_object_type)]
6.2.6.1(p4)
:
Значение может быть скопировано в объект типа unsigned char [n]
(например, по memcpy); результирующий набор байтов называется объектом
представление значения.
Кроме того, Стандарт прямо заявляет, что
Два значения (кроме NaN) с одинаковым представлением объекта
сравнить равные, но значения, которые сравнивают равные, могут иметь разные
представления.
Рассмотрим следующий код:
struct contains_64_t{
uint64_t value;
};
int main(int args, const char *argv[]){
_Alignas(struct contains_64_t)
char buf_2_64t[2 * sizeof(struct contains_64_t)];
struct contains_64_t c64_1;
c64_1.value = 1;
struct contains_64_t c64_2;
c64_2.value = 2;
memcpy(buf_2_64t, &c64_1, sizeof(c64_1));
memcpy(buf_2_64t + sizeof(c64_1), &c64_2, sizeof(c64_2));
//suitably aligned, ok
struct contains_64_t *c64_ptr = (struct contains_64_t*) buf_2_64t;
printf("Value %"PRIu64"\n", c64_ptr -> value);
}
ВОПРОС: Педантично ли писать такой код? Если нет, с какой проблемой мы можем столкнуться при этом?
Из того, что я вижу,
мы можем привести char*
к struct contains_64_t
, так как он правильно выровнен. Но проблема в том, что объявленный тип buf
равен char[2 * sizeof(struct contains_64_t)]
. Итак, формально говоря, мы не можем получить доступ к buf
через lvalue типа struct contains_64_t *
.
Но это было бы странно, поскольку мы правильно выровняли указатель и буквально идентично представлению объекта. Конечно, мы могли бы объявить struct contains_64_t buf[2];
, но решение не будет работать в случае struct
, содержащего массив переменной длины
UPD: будет ли достаточно выполнить такое выравнивание буфера, если мы предположим, что мы компилируем с GCC?