РЕПЕТИТОР математика физика информатика
Для школьников и студентов. Подтягивание пробелов. ЦЭ, ЦТ, ОГЭ, ЕГЭ.
Идет набор на ЛЕТО. Жмите для подробностей:)
1178 of 1245 menu

Атрибут #[repr(packed)]

Атрибут #[repr(packed)] применяется к структурам и объединениям и указывает компилятору упаковывать поля без добавления дополнительных байтов выравнивания. По умолчанию Rust выравнивает поля структуры так, чтобы каждое поле находилось по адресу, кратному его выравниванию. Это ускоряет доступ к памяти, но увеличивает размер типа. Атрибут #[repr(packed)] убирает это выравнивание, делая структуру максимально компактной.

Работа с полями упакованной структуры является небезопасной, потому что поле может находиться по невыровненному адресу. Чтение такого поля по ссылке или получение ссылки на него может привести к неопределённому поведению. Именно поэтому использование #[repr(packed)] относится к разделу unsafe: для доступа к полям требуется либо копирование значения, либо использование небезопасных операций чтения и записи по невыровненному указателю.

Синтаксис

#[repr(packed)] struct StructName { field1: Type1, field2: Type2, }

Также можно указать конкретное выравнивание:

#[repr(packed(2))] struct StructName { field1: Type1, field2: Type2, }

Пример

Давайте сравним размер обычной структуры и структуры с атрибутом #[repr(packed)]. Обычная структура с полями u8 и u32 занимает 8 байт из-за выравнивания, а упакованная - только 5 байт:

use std::mem::size_of; struct Normal { a: u8, b: u32, } #[repr(packed)] struct Packed { a: u8, b: u32, } fn main() { println!("Normal: {}", size_of::<Normal>()); println!("Packed: {}", size_of::<Packed>()); }

Результат выполнения кода:

Normal: 8 Packed: 5

Пример

Давайте прочитаем поле упакованной структуры. Прямое взятие ссылки на поле запрещено компилятором, но можно скопировать значение поля в локальную переменную, что безопасно:

#[repr(packed)] struct Packed { a: u8, b: u32, } fn main() { let p = Packed { a: 1, b: 2 }; let a = p.a; let b = p.b; println!("a = {}, b = {}", a, b); }

Результат выполнения кода:

a = 1, b = 2

Пример

Давайте получим ссылку на поле упакованной структуры через небезопасный блок. Это возможно, но требует внимательности, поскольку ссылка может указывать на невыровненный адрес:

#[repr(packed)] struct Packed { a: u8, b: u32, } fn main() { let p = Packed { a: 1, b: 2 }; let a_ref = unsafe { &p.a }; println!("a = {}", *a_ref); }

Результат выполнения кода:

a = 1

Пример

Давайте запишем новое значение в поле упакованной структуры через небезопасный блок. Для этого используется запись по невыровненному указателю:

#[repr(packed)] struct Packed { a: u8, b: u32, } fn main() { let mut p = Packed { a: 1, b: 2 }; unsafe { let ptr = &mut p.b as *mut u32; ptr.write_unaligned(42); } let b = p.b; println!("b = {}", b); }

Результат выполнения кода:

b = 42

Смотрите также

  • атрибут repr(C),
    который задаёт C-совместимое представление структуры
  • атрибут repr(transparent),
    который делает структуру прозрачной для ABI
  • функция read_unaligned,
    которая читает значение по невыровненному указателю
  • функция write_unaligned,
    которая записывает значение по невыровненному указателю
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить