#rust
Вопрос:
Похоже, расположение структуры не является линейным. Похоже, что поля структуры в памяти расположены не в том порядке, в каком они записаны в определении структуры. Есть ли способ попросить компилятор сохранить порядок полей? Какое еще решение проблемы вы можете предложить? Что-нибудь читаешь?
use std::borrow::Borrow;
fn main()
{
let header = ObjectHeader
{
x : 1,
h : 2,
a : 3,
f : 4,
w : 5,
body : (),
};
let object = header.form();
let borrowed_header : amp;ObjectHeader = object.borrow();
dbg!( borrowed_header );
}
//
#[ derive( Debug, Clone ) ]
pub struct ObjectGeneric< Body >
{
pub x : i64,
pub h : u32,
pub a : u8,
pub f : u16,
pub w : u32,
pub body : Body,
}
pub type ObjectHeader = ObjectGeneric< () >;
impl ObjectHeader
{
pub fn form( self ) -> Object
{
let body = ObjectBody { j : 10 };
Object
{
x : self.x,
h : self.h,
a : self.a,
f : self.f,
w : self.w,
body,
}
}
}
#[ derive( Debug, Clone ) ]
pub struct ObjectBody
{
pub j : u32,
}
pub type Object = ObjectGeneric< ObjectBody >;
//
impl Borrow< ObjectHeader > for Object
{
fn borrow<'a>( amp;'a self ) -> amp;'a ObjectHeader
{
unsafe
{
dbg!( amp;self );
let result = std::mem::transmute::< amp;'a Object, amp;'a ObjectHeader >( self );
dbg!( amp;result );
result
}
}
}
//
Выход:
[src/main.rs:69] amp;self = ObjectGeneric {
x: 1,
h: 2,
a: 3,
f: 4,
w: 5,
body: ObjectBody {
j: 10,
},
}
[src/main.rs:71] amp;result = ObjectGeneric {
x: 1,
h: 2,
a: 0,
f: 10,
w: 5,
body: (),
}
[src/main.rs:17] borrowed_header = ObjectGeneric {
x: 1,
h: 2,
a: 0,
f: 10,
w: 5,
body: (),
}
Комментарии:
1. Вы просмотрели какую-нибудь документацию? doc.rust-lang.org/reference/type-layout.html
2. Спасибо, @Netwave. Да, но это не объясняет ни того, что поля перетасованы, ни того, какой принцип стоит за перетасовкой.
Ответ №1:
В Rust порядок полей в скомпилированной программе может отличаться от порядка в коде. Я думаю, что на практике компилятор переупорядочивает поля, чтобы уменьшить заполнение
Вы можете использовать директиву repr(C)
для сохранения исходного порядка полей
#[repr(C)]
===
Официальная документация заявляет, что для макета по умолчанию порядок полей не указан :
With the exception of the guarantees provided below, the default layout of structs
is not specified.
Кроме того, вы можете прочитать контроткрытия для сохранения макета и некоторые пояснения о сохранении текущего поведения.
Кроме того, если директива #[repr(C)]
не используется:
- чтобы проверить, что код неправильно зависит от макета, используйте
-Z randomize-layout
флаг. Флаг добавляется Kixiron, он рандомизирует расположение структур.
Комментарии:
1. Может быть, вы можете поделиться подробностями принципа перетасовки?
2. Здесь нет «перетасовки», и то, что делает компилятор, является детализацией реализации, но в настоящее время он просто упорядочивает поля по величине в первую очередь. Это уменьшает размер структуры (путем ограничения заполнения), не изменяя ее семантику и не требуя, чтобы разработчик нарушал «логический» порядок структуры.
3. Кроме того, помимо таких вещей, как размер сетевого протокола или любая обработка только двоичных файлов, где размер имеет решающее значение, наличие важного порядка элементов структуры обычно указывает на другие маргинальные методы, такие как каламбур типа или копирование между типами с помощью memcpy. Если вы следуете рекомендациям и доверяете компилятору, вам не следует делать ни того, ни другого, и, следовательно, ваши макеты структур не должны быть важными. Только при «общении» вне вашей программы на двоичном языке (или языке, таком как взаимодействие с C) макет становится важным.