【问题标题】:Casting of struct to specific address of byte slice将结构转换为字节片的特定地址
【发布时间】:2020-03-23 12:18:08
【问题描述】:

为了解析一个巨大的文件而不必为每个结构复制字节,我想将结构直接转换为字节片中的地址。这仅是出于性能原因。 我知道我可以使用 binary.Read() 从字节切片创建结构,但据我所知,这将复制字节,这是一件昂贵的事情;因此我想避免在这个用例中使用这种方法。

我似乎确实已经转换了结构,因为我确实得到了我期望的结构中的数据。但是,当我更改结构中的值时,它们不会更改结构地址应指向的字节片吗?对我来说重要的是文件(字节切片)反映了我的结构中数据的变化。

我怎样才能让结构在文件中的相应地址上工作?

这是我到目前为止所做的演示:

type T struct {
    A uint8
}

func main() {

    data := []byte{0xA, 0xB, 0xC}

    // Cast bytes to struct
    pointer := *(*uint8)(unsafe.Pointer(&data[0]))
    fmt.Printf("ptr:\t0x%x\n", pointer)

    t2 := *(*T)(unsafe.Pointer(&pointer))
    fmt.Printf("T:\t0x%x\n\n", t2.A)
    // byte casting to struct ends here

    // test
    t2.A = 0x0 // I expect this to change for data as well but it does not.

    fmt.Println("AFTER CHANGE OF t2.A")
    fmt.Printf("data[0]:0x%x\n", data[0])
    fmt.Printf("ptr:\t0x%x\n\n", pointer)

    fmt.Println("WHY ARE THESE ON DIFFERENT ADDRESSES?")
    fmt.Printf("DataAddr: 0x%p\n", data)
    fmt.Printf("PtrAddr: 0x%p\n", &pointer)
    fmt.Printf("T2Addr: 0x%p\n", &t2)

}

打印出来:

ptr:    0xa
T:      0xa

AFTER CHANGE OF t2.A - the original data slice has not been altered.
data[0]:0xa
ptr:    0xa

ADDRESSES
DataAddr: 0x0xc000094010
PtrAddr: 0x0xc000094013
T2Addr: 0x0xc000094030

【问题讨论】:

    标签: pointers go struct casting slice


    【解决方案1】:

    你正确地转换了指针,然后你取消引用它,这会产生一个副本。然后你继续获取副本的地址,转换该指针并再次取消引用它(这会产生另一个副本)。修改任何副本不会对其他副本产生任何影响。

    所以不要取消引用指针(最终我们只是修改 pointed 值,它们将位于同一内存位置):

    data := []byte{0xA, 0xB, 0xC}
    
    // Cast bytes to struct
    pointer := (*uint8)(unsafe.Pointer(&data[0]))
    fmt.Printf("ptr:\t0x%x\n", *pointer)
    
    t2 := (*T)(unsafe.Pointer(pointer))
    fmt.Printf("T:\t0x%x\n\n", t2.A)
    // byte casting to struct ends here
    
    // test
    t2.A = 0x0 // This will also change data
    
    fmt.Println("AFTER CHANGE OF t2.A")
    fmt.Printf("data[0]:0x%x\n", data[0])
    fmt.Printf("ptr:\t0x%x\n\n", *pointer)
    
    fmt.Println("ADDRESSES ARE ALL THE SAME:")
    fmt.Printf("DataAddr: 0x%p\n", &data[0])
    fmt.Printf("PtrAddr: 0x%p\n", pointer)
    fmt.Printf("T2Addr: 0x%p\n", t2)
    

    输出(在Go Playground 上试试):

    ptr:    0xa
    T:  0xa
    
    AFTER CHANGE OF t2.A
    data[0]:0x0
    ptr:    0x0
    
    ADDRESSES ARE ALL THE SAME:
    DataAddr: 0x0x40e020
    PtrAddr: 0x0x40e020
    T2Addr: 0x0x40e020
    

    【讨论】:

    • 非常感谢您的迅速回复。非常感谢您的回答!
    猜你喜欢
    • 2020-08-25
    • 1970-01-01
    • 2011-02-11
    • 2018-05-22
    • 2014-12-31
    • 1970-01-01
    • 2012-11-26
    • 1970-01-01
    • 2013-12-11
    相关资源
    最近更新 更多