(gcc)go 中的打包结构

发布于 2024-11-20 00:21:45 字数 397 浏览 5 评论 0原文

我有一些旧的 C 代码,它们在某种程度上大量使用了打包结构。我正在考虑使用 Go 作为此代码的包装器,但很难找到传递甚至编写这些结构的定义的方法。

示例:

import "unsafe";

type AlignTest struct {
    c byte;
    y int16;
    z int16;
    q int32;
}

func main() {

    vr := new(AlignTest);

    fmt.Println(unsafe.Sizeof(*vr),  "\n");

}

返回 12,而不是我想要的打包/未对齐结构的 1+2+2+4 = 9。

我知道我可以创建一个字节数组并手动进行解析,但这似乎非常脆弱且容易出错......

I have some old C code that makes somewhat heavy use of packed structures. I'm looking into using Go as a wrapper for this code, but am having difficulty finding a way to pass or even write definitions for these structures.

Example:

import "unsafe";

type AlignTest struct {
    c byte;
    y int16;
    z int16;
    q int32;
}

func main() {

    vr := new(AlignTest);

    fmt.Println(unsafe.Sizeof(*vr),  "\n");

}

Returns 12 rather than the 1+2+2+4 = 9 that I would want with a packed/unaligned struct.

I know that I could just create a byte array and do the parsing manually, but that seems very brittle and error prone...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

不醒的梦 2024-11-27 00:21:45

你可以尝试这样的事情。

package main

import (
    "encoding/binary"
    "bytes"
    "fmt"
)

type Unpacked struct {
    C byte
    Y int16
    Z int16
    Q int32
}

type Packed struct {
    B [9]byte
}

func main() {
    var u Unpacked
    var p Packed
    var buf = bytes.NewBuffer(make([]byte, 0, len(p.B)))
    // Unpacked to Packed 
    u = Unpacked{1, 2, 3, 4}
    if err := binary.Write(buf, binary.BigEndian, &u); err != nil {
        fmt.Println(err)
    }
    if err := binary.Read(buf, binary.BigEndian, &p); err != nil {
        fmt.Println(err)
    }
    fmt.Println("u", u, "to", "p", p)
    // Packed to Unpacked
    p = Packed{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9}}
    if err := binary.Write(buf, binary.BigEndian, &p); err != nil {
        fmt.Println(err)
    }
    if err := binary.Read(buf, binary.BigEndian, &u); err != nil {
        fmt.Println(err)
    }
    fmt.Println("p", p, "to", "u", u)
}

Output:
u {1 2 3 4} to p {[1 0 2 0 3 0 0 0 4]}
p {[1 2 3 4 5 6 7 8 9]} to u {1 515 1029 101124105}

You could try something like this.

package main

import (
    "encoding/binary"
    "bytes"
    "fmt"
)

type Unpacked struct {
    C byte
    Y int16
    Z int16
    Q int32
}

type Packed struct {
    B [9]byte
}

func main() {
    var u Unpacked
    var p Packed
    var buf = bytes.NewBuffer(make([]byte, 0, len(p.B)))
    // Unpacked to Packed 
    u = Unpacked{1, 2, 3, 4}
    if err := binary.Write(buf, binary.BigEndian, &u); err != nil {
        fmt.Println(err)
    }
    if err := binary.Read(buf, binary.BigEndian, &p); err != nil {
        fmt.Println(err)
    }
    fmt.Println("u", u, "to", "p", p)
    // Packed to Unpacked
    p = Packed{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9}}
    if err := binary.Write(buf, binary.BigEndian, &p); err != nil {
        fmt.Println(err)
    }
    if err := binary.Read(buf, binary.BigEndian, &u); err != nil {
        fmt.Println(err)
    }
    fmt.Println("p", p, "to", "u", u)
}

.

Output:
u {1 2 3 4} to p {[1 0 2 0 3 0 0 0 4]}
p {[1 2 3 4 5 6 7 8 9]} to u {1 515 1029 101124105}
月牙弯弯 2024-11-27 00:21:45

您可能想要重新考虑您的架构 - 尝试将二进制输入向下传递到 C 层并使用现有结构(您不会破坏不更改的内容)。我假设结构打包看起来像这样:

#ifdef WINDOWS
#pragma pack(push)
#endif
#pragma pack(BYTEALIGNMENT) // e.g. "#pragma pack(1)" or "#pragma pack(8)"

//--- Some packed structs

#ifdef WINDOWS
#pragma pack(pop)
#endif
#ifdef POSIX
#pragma pack()
#endif

所有底层或第 3 方库所做的就是获取一些 void* 或 const char* 并将其类型转换为这些。因此,如果可能的话,尝试将该数据转发到 C 层(您可以在其中获取指针)并且根本不公开结构。

You may want to rethink your architecture- try passing the binary input down to the C layer and use the existing structures (you won't break what you don't change). I'm assuming the structure packing looks something like this:

#ifdef WINDOWS
#pragma pack(push)
#endif
#pragma pack(BYTEALIGNMENT) // e.g. "#pragma pack(1)" or "#pragma pack(8)"

//--- Some packed structs

#ifdef WINDOWS
#pragma pack(pop)
#endif
#ifdef POSIX
#pragma pack()
#endif

All the underlying or 3rd Party libs are then doing is taking some void* or const char* and typecasting it to these. So if possible, try forwarding that data into a C layer (where you can get pointers) and don't expose the structures at all.

英雄似剑 2024-11-27 00:21:45

没有办法告诉 gccgo 编译打包结构。我能想到的最好的解决方案是手动添加填充:

type AlignTest struct {
    c byte
    _ [3]byte // anonymous padding
    y int16
    z int16
    q int32
}

There's no way to tell gccgo to compile packed structures. The best solution I can think of is to manually add padding:

type AlignTest struct {
    c byte
    _ [3]byte // anonymous padding
    y int16
    z int16
    q int32
}
小鸟爱天空丶 2024-11-27 00:21:45

这有效:

package main

import "unsafe"
import "fmt"

/*
struct test {
    char c;
    short i;
    short j;
    int k;
} __attribute__((packed));
*/
import "C"

type AlignTest struct {
    c byte
    y int16
    z int16
    q int32
}

func main() {

    vr := new(AlignTest)
    v := new(C.struct_test)

    fmt.Println(unsafe.Sizeof(*vr), "\n")
    fmt.Println(unsafe.Sizeof(*v), "\n")

}

输出:

12

9

This works:

package main

import "unsafe"
import "fmt"

/*
struct test {
    char c;
    short i;
    short j;
    int k;
} __attribute__((packed));
*/
import "C"

type AlignTest struct {
    c byte
    y int16
    z int16
    q int32
}

func main() {

    vr := new(AlignTest)
    v := new(C.struct_test)

    fmt.Println(unsafe.Sizeof(*vr), "\n")
    fmt.Println(unsafe.Sizeof(*v), "\n")

}

Output:

12

9
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文