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