2014-09-18 58 views
4

原始字節我有一個結構,看起來像這樣:充分利用包裝的結構

#[repr(packed)] 
struct Header { 
    some: u8, 
    thing: u8, 
} 

我怎樣才能從它那裏得到原始字節,那我可以用任何一個C庫或插座互動?

我希望用transmute來解決問題,但不幸的是,這並不工作:

let header = Header {....} 
let header_bytes: &[u8] = unsafe { mem::transmute(header) }; 
let result = self.socket.write(header_bytes); 

這種失敗

error: transmute called on types with different sizes: &Header (64 bits) to &[u8] (128 bits) 

回答

7

編輯:更新爲鏽1.x.

不能蛻變任意一點到任意事物(如Header&[u8]),因爲transmute()是類似於在C reinterpret_cast ++:它的字面重新詮釋其它的參數包括字節,並且爲了這個成功的源目標類型應該具有相同的大小。但即使Header&[u8]具有相同的大小,在它們之間進行轉換也沒有意義:Header是實際值,而&[u8]是指針後面的數據大小的指針。

爲了解釋的一塊數據作爲需要執行三個步驟的字節切片:得到生指針的數據,將其轉換爲一個指針u8,然後將其轉換成的u8切片。這意味着使用長度來增強原始指針值,在這種情況下,該長度等於結構大小。最後一步可以很容易地完成std::slice::from_raw_parts()

use std::slice; 
use std::mem; 

let p: *const Header = &header;  // the same operator is used as with references 
let p: *const u8 = p as *const u8; // convert between pointer types 
let s: &[u8] = unsafe { 
    slice::from_raw_parts(p, mem::size_of::<Header>()) 
}; 

然而,在大多數情況下,這樣做是不是一個好主意。儘管結構被標記爲壓縮,但它仍然留下字節順序的問題,所以至少這樣做的代碼不會是可移植的(或者說,它以這種形式序列化的數據可能無法恢復爲另一個體繫結構編譯相同的程序)。

+0

你有沒有機會知道現在應該怎麼做?檢查它說'std :: slice :: raw :: buf_as_slice'的文檔已被棄用,但不提供任何其他選擇。 – 2016-03-08 17:09:29

+1

@HarveyAdcock,我已經更新了Rust最新的答案。在穩定的語言中,從原始指針獲取切片的首選方法是'std :: slice :: from_raw_parts()'。 – 2016-03-08 20:16:56

+0

感謝您的更新。如果這不是一個好主意,那麼如果我試圖將堆棧中的結構複製到更持久的受管理的內存部分中,您還有什麼建議?我正在做一個簡單的內存分配器,所以我想我必須處理像這樣複製字節。 – 2016-03-09 00:08:21

0

你可以做任何對象爲一個byte切片用一個這樣的功能:

/// Safe to use with any wholly initialized memory `ptr` 
unsafe fn raw_byte_repr<'a, T>(ptr: &'a T) -> &'a [u8] 
{ 
    std::mem::transmute(std::raw::Slice{ 
     data: ptr as *const _ as *const u8, 
     len: std::mem::size_of::<T>(), 
    }) 
} 

Run in Rust playpen.

我不知道完整的安全分析,但只要你不訪問任何uninit值應該沒問題。