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);
}
}