Rust 0长数组使用 以及与C的0长数组区别。
0长数组在C中很常见很实用,但是在Rust这种强调安全性的语言中,很难定义以及使用,一般都无法编译通过。但是一些与系统相关的函数又必须使用类似的操作。所以Rust提供了unsafe系列的函数方便来读取他们。
在C中0长数组通常定义如下:
struct line { int length; //长度 char contents[0]; //待扩展内存 }; //The following if using Flexible Array Member of C99 struct line { int length; char contents[]; };
Clang这时候只需要把指针对应到结构体上,即可用数组下标方式访问内容里面每一个字符。
Rust定义:
#[repr(C)] pub struct line { pub length: c_int, pub content: [c_char;0], } //or #[repr(C)] pub struct line { pub length: c_int, pub content: [u8;0], }
然后转换函数:
let line: *const line = ... //常规结构体 let len = unsafe { (*line).length as usize }; //数组长度 let ptr = unsafe { std::mem::transmute::<&[c_char;0], *const u8>( (*line).content ) }; //内容转为指针 let slice = unsafe { std::slice::from_raw_parts( ptr, len ) }; //内容转为数组片段
但是Rust需要在unsafe 块中使用转换函数,且数组结构体需要分离出来访问才行
总的来说Rust 转指针转数组指针都必须用unsafe的函数
内存地址转指针用:std::mem::transmute
内存地址转数组:std::slice::from_raw_parts
附上rust获取winapi gettcptable2 的例子:
unsafe { let mut pTcpTable :PMIB_TCPTABLE2; let mut ulSize :ULONG; let mut dwRetVal :DWORD ; pTcpTable = libc::malloc( mem::size_of::<MIB_TCPTABLE2>() as libc::size_t ) as PMIB_TCPTABLE2; if pTcpTable.is_null() { println!("Error allocating memory"); return false; } ulSize = mem::size_of::<MIB_TCPTABLE>() as DWORD; dwRetVal = GetTcpTable2(pTcpTable, &mut ulSize, TRUE); if dwRetVal == ERROR_INSUFFICIENT_BUFFER { libc::free(pTcpTable as *mut libc::c_void); pTcpTable = libc::malloc( ulSize as libc::size_t ) as PMIB_TCPTABLE2; if pTcpTable.is_null() { println!("Error allocating memory"); return false; } } dwRetVal = GetTcpTable2(pTcpTable, &mut ulSize, TRUE); if dwRetVal == NO_ERROR { println!("Number of entries: {}", (*pTcpTable).dwNumEntries); let entries_size = (*pTcpTable).dwNumEntries as usize; let tables_ptr = (*pTcpTable).table.as_ptr(); let tcp_tables = std::slice::from_raw_parts( tables_ptr, entries_size ) ; for i in 0 .. entries_size { print!("[{}] State: {} - ", i, tcp_tables[i].dwState); match tcp_tables[i].dwState { MIB_TCP_STATE_CLOSED=>print!("CLOSED"), MIB_TCP_STATE_LISTEN=>print!("LISTEN"), MIB_TCP_STATE_SYN_SENT=>print!("SYN-SENT"), MIB_TCP_STATE_SYN_RCVD=>print!("SYN-RECEIVED"), MIB_TCP_STATE_ESTAB=>print!("ESTABLISHED"), MIB_TCP_STATE_FIN_WAIT1=>print!("FIN-WAIT-1"), MIB_TCP_STATE_FIN_WAIT2=>print!("FIN-WAIT-2 "), MIB_TCP_STATE_CLOSE_WAIT=>print!("CLOSE-WAIT"), MIB_TCP_STATE_CLOSING=>print!("CLOSING"), MIB_TCP_STATE_LAST_ACK=>print!("LAST-ACK"), MIB_TCP_STATE_TIME_WAIT=>print!("TIME-WAIT"), MIB_TCP_STATE_DELETE_TCB => print!("DELETE-TCB"), _ => print!("UNKNOWN dwState value"), } let local_addr :IPAddr = std::mem::transmute(tcp_tables[i].dwLocalAddr); print!("\t Local Addr: {:?}", local_addr); print!("\t Local Port: {} ", u16::from_be(tcp_tables[i].dwLocalPort as u16)); let remote_addr :IPAddr = std::mem::transmute(tcp_tables[i].dwLocalAddr); print!("\t Remote Addr: {:?}", remote_addr); print!("\t Remote Port: {}", u16::from_be(tcp_tables[i].dwRemotePort as u16)); print!("\t Owning PID: {:?}\t", tcp_tables[i].dwOwningPid); match tcp_tables[i].dwOffloadState { TcpConnectionOffloadStateInHost=> println!("Owned by the network stack and not offloaded "), TcpConnectionOffloadStateOffloading=> println!("In the process of being offloaded"), TcpConnectionOffloadStateOffloaded=> println!("Offloaded to the network interface control"), TcpConnectionOffloadStateUploading=> println!("In the process of being uploaded back to the network stack "), _ => println!("UNKNOWN Offload state value"), } } } else { println!("\tGetTcpTable2 failed with {}", dwRetVal); libc::free(pTcpTable as *mut libc::c_void); return false; } if !pTcpTable.is_null() { libc::free(pTcpTable as *mut libc::c_void); } }