【问题标题】:Golang - structs, initializing and memcpy - what is the proper way?Golang - 结构,初始化和 memcpy - 什么是正确的方法?
【发布时间】:2015-06-18 07:16:40
【问题描述】:

我是 Go 新手,我想翻译一些我必须 Go 但我没能做到的 C/C++ 代码。问题存在于两个地方:如何初始化我定义的结构以及如何执行“memcopy”

我说的代码是这样的:http://play.golang.org/p/e8N255qEAk 第 69 和 74 行。

我想“翻译”成 Go 的 C/C++ 代码是这样的:

            typedef char xchr;
            typedef int xint;
            typedef double xdob;
            typedef float xflt;
            typedef struct
            {
               xint p; 
               xdob lat_lon_ele[3];
               xflt psi_the_phi[3];
               xflt gear_flap_vect[3];
            }VEH1;

            avio.p = 0;
            avio.lat_lon_ele[0] = 47.460058;
            avio.lat_lon_ele[1] = -122.32104;
            avio.lat_lon_ele[2] = 8000.000;

            avio.psi_the_phi[0] = 110.5;
            avio.psi_the_phi[1] = 0.0;
            avio.psi_the_phi[2] = 0.0;

            avio.gear_flap_vect[0] = 1.0;
            avio.gear_flap_vect[1] = 0.0;
            avio.gear_flap_vect[2] = 0.0;

            VEH1* av = &avio;

            xchr data_send[6];
            data_send[0]='V';
            data_send[1]='E';
            data_send[2]='H';
            data_send[3]='1';
            data_send[4]=0;

            memcpy(&data_send[5],av,sizeof(VEH1)); // load in the data

Go 代码如下所示:

            type xchr int8
            type xint int
            type xdob float64
            type xflt float32

            type VEH1 struct {
                p              xint
                lat_lon_ele    [3]xdob
                psi_the_phi    [3]xflt
                gear_flap_vect [3]xflt
            }

            type VEHA struct {
                num_p xint

                lat_lon_ele    [10][3]xdob
                psi_the_phi    [10][3]xflt
                gear_flap_vect [10][3]xflt

                lat_view, lon_view, ele_view xdob
                psi_view, the_view, phi_view xflt
            }


            var avio VEH1
            avio = &VEH1{0, {47.460058, -122.32104, 8000.000}, {110.5, 0.0, 0.0}, {1.0, 0.0, 0.0}}

            data_send := [6]xchr{'V', 'E', 'H', '1', 0, 0}
            copy(data_send[5:5], avio);

谢谢!

【问题讨论】:

    标签: arrays struct go initialization custom-type


    【解决方案1】:

    所以基本上给出了这些基本类型:

    type xchr int8
    type xint int
    type xdob float64
    type xflt float32
    

    您要复制以下struct 类型的值的字节(内存表示):

    type VEH1 struct { // 52 bytes total
        p              xint    // 4 bytes (READ BELOW)
        lat_lon_ele    [3]xdob // 24 bytes
        psi_the_phi    [3]xflt // 12 bytes
        gear_flap_vect [3]xflt // 12 bytes
    }
    

    请注意,Go 中 int 的长度取决于平台,它可能是 32 位或 64 位,具体取决于您编译到的目标架构。这将导致依赖于平台的行为,所以我们现在将其修复为 int32

    type xint int32
    

    以上struct的字节大小就是这样计算的。如果您需要int64,只需更改它并在大小计算中添加 4 个额外的字节。

    接下来,您希望将结果放在元素类型为 xchr 的数组中。您需要一个足够大的数组,即“前缀”为"VEH1",后跟上述struct 的数据。所以它的大小必须为4+sizeof(VEH1),即56

    在 Go 中将一种类型的字节复制到另一种类型的内存空间中,您可以使用 unsafe 包及其一般的 Pointer 类型。任何指针都可以转换为unsafe.Pointerunsafe.Pointer 可以转换为任何指针类型,因此这是您在不同指针类型之间的“网关”。

    您可以获取VHE1struct 值的地址,将其转换为Pointer,并将结果Pointer 转换为指向目标数据类型的指针。取消引用指针,现在您已经有了其他类型的值。

    内置的copy() 只能与切片一起使用,因此首先您需要对数据数组进行切片以便能够将它们传递给copy()

    你可以这样做:

    avio := VEH1{0, [3]xdob{47.460058, -122.32104, 8000.000},
        [3]xflt{110.5, 0.0, 0.0}, [3]xflt{1.0, 0.0, 0.0}}
    fmt.Printf("%+v\n", avio)
    
    pavio := unsafe.Pointer(&avio)
    pavio_arr := *((*[52]xchr)(pavio))
    
    data_send := [56]xchr{'V', 'E', 'H', '1'}
    n := copy(data_send[4:], pavio_arr[:])
    fmt.Printf("Copied %d bytes\n", n)
    
    fmt.Printf("%+v\n", data_send)
    

    输出,包装以适应屏幕:

    {p:0 lat_lon_ele:[47.460058 -122.32104 8000] psi_the_phi:[110.5 0 0]
        gear_flap_vect:[1 0 0]}
    Copied 52 bytes
    [86 69 72 49 0 0 0 0 0 0 0 0 -81 33 56 46 -29 -70 71 64 77 45 91 -21 -117
        -108 94 -64 0 0 0 0 0 64 -65 64 0 0 -35 66 0 0 0 0 0 0 0 0 0 0 -128 63 0 0 0 0]
    

    Go Playground 上尝试工作演示。

    结果为@​​987654352@

    如果您想要[]byte 结果(例如,您想将结果写入io.Writer),则使用[56]byte 类型作为data_send,当然还有将pavio 转换为*[52]byte

    pavio := unsafe.Pointer(&avio)
    pavio_arr := *((*[52]byte)(pavio))
    
    data_send := [56]byte{'V', 'E', 'H', '1'}
    n := copy(data_send[4:], pavio_arr[:])
    

    【讨论】:

    • 谢谢你,icza!留给我的唯一一件事就是将 data_send 写入套接字。我现在正在寻找有关如何将其打包成 []byte 的解决方案
    • @emmerich 如果您将type xchr int8 更改为type xchr byte,那么您将已经拥有[]byte
    • 不幸的是,它不喜欢我的自定义类型,即使是 byte 也不能在 conn.conn.Write 的参数中使用 data_send (type [57]xchr) 作为 type []byte 另外,我已经在此之前尝试使用: buf := new(bytes.Buffer) if err := binary.Write(buf, binary.BigEndian, &data_send); err != nil { fmt.Println(err) os.Exit(1) } _, err = conn.Write(buf.Bytes()) 另外,使用 tcpdump 我注意到 C++ 之间的长度相差 4 个字节版本和 Go 版本:pastebin
    • @emmerich 查看编辑后的答案,结果为[]byte,变化很小。
    • Int 固定长度并且行为确定性的,但它依赖于平台
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-15
    • 2011-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多