确定[] byte

时间:2017-04-18 14:25:06

标签: go slice sizeof

我有一些代码可以解压缩从UDP套接字读取的消息,包括设备MAC地址(设备存储在消息本身中)。我发现只需将[]byte切片分配给struct成员就可以复制缓冲区中MAC地址的地址。我可以使用copy()原语复制该值,这仅在我首先在目标中分配存储时才有效。以下代码有效:

// You can edit this code!
// Click here and start typing.
package main

import (
    "fmt"
    "net"
)

// information about an Orvibo S20 IoT device
type Device struct {
    Mac, ReverseMac net.HardwareAddr // MAC address (and reversed)
    IsOn            bool             // power state
}

// function to unpack the info from the Discover reply
func unpackDiscoverResp(buff []byte) Device {
    d := Device{}
    d.Mac = make([]byte, 6)
    copy(d.Mac, buff[7:7+6])
    d.ReverseMac = make([]byte, 6)
    copy(d.ReverseMac, buff[7+12:7+6+12])
    d.IsOn = buff[41] != 0
    return d
}

func main() {
    s1 := []byte{
        0x68, 0x64, 0x00, 0x2a, 0x71, 0x61, 0x00, 0xac, 0xcf, 0x23, 0x36, 0x02, 0x0e, 0x20, 0x20, 0x20,
        0x20, 0x20, 0x20, 0x0e, 0x02, 0x36, 0x23, 0xcf, 0xac, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,
        0x4f, 0x43, 0x30, 0x30, 0x35, 0x2e, 0xe1, 0x9d, 0xdc, 0x00}
    s2 := []byte{
        0x68, 0x64, 0x00, 0x2a, 0x71, 0x61, 0x00, 0xac, 0xcf, 0x23, 0x55, 0xfe, 0x22, 0x20, 0x20, 0x20,
        0x20, 0x20, 0x20, 0x22, 0xfe, 0x55, 0x23, 0xcf, 0xac, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,
        0x4f, 0x43, 0x30, 0x30, 0x35, 0x39, 0x87, 0x1b, 0xbc, 0x01}

    msgs := [][]byte{s1, s2}

    devices := make([]Device, 0)

    for _, msg := range msgs {
        d := unpackDiscoverResp(msg)
        devices = append(devices, d)
        fmt.Println(d)
    }

    //d1 := unpackDiscoverResp(s1)
    //devices = append(devices, d1)
    //d2 := unpackDiscoverResp(s2)
    //devices = append(devices, d2)
    //fmt.Println(d1)
    fmt.Println(devices)

}

https://play.golang.org/p/vMdNlX5H2H 我不喜欢的部分是第19行(和21)

d.Mac = make([]byte, 6)

在我看来,这必须是常见模式,应该有办法获得存储所需的大小。因为我已经对我正在复制的切片长度进行了硬编码,所以我认为硬编码所需的存储空间并不差,但从更一般的意义上来说,我更愿意做得更好。 (在C中我使用sizeof运算符,但这不是C。)

谢谢!

3 个答案:

答案 0 :(得分:2)

您可以使用len()吗?

newBuf := make([]byte,len(oldBuf))
copy(newBuf, oldBuf)

如果您有更复杂的要求,请解释一下。

答案 1 :(得分:2)

在Go中使用内置len()函数。存储切片的结果,并在其上使用len()

func unpackDiscoverResp(buff []byte) Device {
    d := Device{}

    mac := buff[7:7+6]
    d.Mac = make([]byte, len(mac))
    copy(d.Mac, mac)

    reverseMac := buff[7+12:7+6+12]
    d.ReverseMac = make([]byte, len(reverseMac))
    copy(d.ReverseMac, reverseMac)

    d.IsOn = buff[41] != 0
    return d
}

但是如果你只想复制它,只需附加到nil切片就更容易/更短(内置append()函数根据需要分配存储空间):

func unpackDiscoverResp(buff []byte) Device {
    d := Device{}
    d.Mac = append(d.Mac, buff[7:7+6]...)
    d.ReverseMac = append(d.ReverseMac, buff[7+12:7+6+12]...)
    d.IsOn = buff[41] != 0
    return d
}

或者只是在复合文字中:

d := Device{
    Mac:        append([]byte(nil), buff[7:7+6]...),
    ReverseMac: append([]byte(nil), buff[7+12:7+6+12]...),
}

有一点需要注意:append()可能会分配比所需更大的后备数组(它会为将来的附加“优化”),所以如果你想避免这种情况,第一个解决方案是{{1}更好。

答案 2 :(得分:0)

谢谢 - len()是关键。我用

替换了原始代码
// copyMac allocates space for and copies MAC addr from slice
func copyMac(dst *net.HardwareAddr, src []byte) {
    *dst = make([]byte, len(src))
    copy(*dst, src)
}

// Code to find and send commands to Orvibo S20 WiFi controlled outlets
// The outlets need to brought into the network first (AKA paired)
// and for that see pair.go
func unpackDiscoverResp(ip *net.UDPAddr, buff []byte) Device {
    d := Device{IpAddr: *ip}
    copyMac(&d.Mac, buff[7:7+6])
    copyMac(&d.ReverseMac, buff[7+12:7+6+12])
    d.IsOn = buff[41] != 0
    return d
}

我比我原来的代码更开心。 (我确实需要修复那个已失去与代码连接的注释。)