将结构投射到字节片的特定地址

问题描述 投票:1回答:1

要解析一个大文件而不必为每个结构复制字节,我想将结构直接转换为字节片中的地址。这完全是出于性能原因。我知道我可以使用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个回答
0
投票

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

因此,请不要取消对指针的引用(最终我们只需修改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
© www.soinside.com 2019 - 2024. All rights reserved.