Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions examples/basic/unsafes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

| file | example name | note |
| ---------------------- | ------------------- | -------------------------------------------------------------------- |
| unsafe_sizeof.go | unsafe_sizeof | unsafe.Sizeof() についてのサンプルです. |
| unsafe_string.go | unsafe_string | unsafe.String() のサンプルです. |
| unsafe_stringdata.go | unsafe_stringdata | unsafe.StringData() のサンプルです. |
| unsafe_pointer_cast.go | unsafe_pointer_cast | unsafeパッケージを用いてポインタを任意の型にキャストするサンプルです |
| unsafe_add.go | usnafe_add | unsafe.Add関数を利用してポインタ演算するサンプルです |
| unsafe_slice.go | usnafe_slice | unsafe.SliceData() と unsafe.Slice() のサンプルです |
| unsafe_add.go | unsafe_add | unsafe.Add関数を利用してポインタ演算するサンプルです |
| unsafe_slice.go | unsafe_slice | unsafe.SliceData() と unsafe.Slice() のサンプルです |
| unsafe_sizeof.go | unsafe_sizeof | unsafe.Sizeof() についてのサンプルです. |
| unsafe_offsetof.go | unsafe_offsetof | unsafe.Offsetof() のサンプルです |
| unsafe_dump.go | unsafe_dump | unsafeパッケージを使って構造体のメモリダンプを出力するサンプルです |
2 changes: 2 additions & 0 deletions examples/basic/unsafes/examples.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ func (r *register) Regist(m mapping.ExampleMapping) {
m["unsafe_pointer_cast"] = PointerCast
m["unsafe_add"] = Add
m["unsafe_slice"] = Slice
m["unsafe_offsetof"] = Offsetof
m["unsafe_dump"] = Dump
}
77 changes: 77 additions & 0 deletions examples/basic/unsafes/unsafe_dump.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package unsafes

import (
"encoding/hex"
"fmt"
"math"
"os"
"unsafe"
)

// Dump は、unsafeパッケージを使って構造体のメモリダンプを出力するサンプルです。
func Dump() error {
type (
// わざとパディングが入る構造体とする
// size: 24bytes
S1 struct {
A uint8 // offset=0, size=1, padding=3
B uint32 // offset=4, size=4, padding=0
C uint64 // offset=8, size=8, padding=0
D uint16 // offset=16, size=2, padding=6
}
)

// 構造体のメモリダンプ
// 尚、実行すると以下のように
// 00000000 ff 62 a6 00 ff ff ff ff ff ff ff ff ff ff ff ff
// 00000010 ff ff 1e 00 c0 00 00 00
// 62 a6 のようなゴミが見える。これはGoはパディング部分をゼロ初期化しないため。
// Goの仕様では、構造体のフィールドは初期化されるが、アライメントのためのパディング領域は未定義となっている。
var (
s1 = S1{math.MaxUint8, math.MaxUint32, math.MaxUint64, math.MaxUint16}
size = unsafe.Sizeof(s1)
ptr = unsafe.Pointer(&s1)
bytePtr = (*byte)(ptr)
byteSlice = (([]byte)(unsafe.Slice(bytePtr, size)))
)
hex.Dumper(os.Stdout).Write(byteSlice)
fmt.Println("")

// ゼロクリアしてから値を再設定して確認してみる
// 以下のループはmemset(ptr, 0, size) と同じ感じ。
for i := range int(size) {
if i == 0 {
*bytePtr = 0
}

ptr = unsafe.Add(ptr, 1)
bytePtr = (*byte)(ptr)
*bytePtr = 0
}

// 構造体の値を設定しなおし
s1.A = math.MaxUint8
s1.B = math.MaxUint32
s1.C = math.MaxUint64
s1.D = math.MaxUint16

hex.Dumper(os.Stdout).Write(byteSlice)

return nil

/*
$ task
task: [build] go build -o "/home/dev/dev/github/try-golang/try-golang" .
task: [run] ./try-golang -onetime

ENTER EXAMPLE NAME: unsafe_dump

[Name] "unsafe_dump"
00000000 ff 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff |................|
00000010 ff ff 18 00 c0 00 00 00
00000000 ff 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff |................|
00000010 ff ff 00 00 00 00 00 00

[Elapsed] 88.436µs
*/
}
65 changes: 65 additions & 0 deletions examples/basic/unsafes/unsafe_offsetof.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package unsafes

import (
"fmt"
"math"
"unsafe"
)

// Offsetof は、unsafe.Offsetof() のサンプルです。
//
// > Offsetof returns the offset within the struct of the field represented by x, which must be of the form structValue.field.
// > In other words, it returns the number of bytes between the start of the struct and the start of the field.
// > The return value of Offsetof is a Go constant if the type of the argument x does not have variable size.
//
// > Offsetof は、引数 x によって表される構造体内のフィールドのオフセットを返します。引数 x は、必ず structValue.field の形式でなければなりません。
// > 言い換えると、これは構造体の先頭からそのフィールドの先頭までのバイト数を返します。
// > Offsetof の戻り値は、引数 x の型が可変サイズを持たない場合、Goの定数になります。
//
// REFERENCES:
// - https://pkg.go.dev/unsafe@go1.25.3#Offsetof
func Offsetof() error {
type (
// わざとパディングが入る構造体とする
// size: 24bytes
S1 struct {
A uint8 // offset=0, size=1, padding=3
B uint32 // offset=4, size=4, padding=0
C uint64 // offset=8, size=8, padding=0
D uint16 // offset=16, size=2, padding=6
}
)
var (
s1 = S1{math.MaxUint8, math.MaxUint32, math.MaxUint64, math.MaxUint16}
off1 = unsafe.Offsetof(s1.A)
off2 = unsafe.Offsetof(s1.B)
off3 = unsafe.Offsetof(s1.C)
off4 = unsafe.Offsetof(s1.D)
size = unsafe.Sizeof(s1)
)
fmt.Printf("S1.A: %d\n", off1)
fmt.Printf("S1.B: %d\n", off2)
fmt.Printf("S1.C: %d\n", off3)
fmt.Printf("S1.D: %d\n", off4)
fmt.Printf("size: %d\n", size)

return nil

/*
$ task
task: [build] go build -o "/home/dev/dev/github/try-golang/try-golang" .
task: [run] ./try-golang -onetime

ENTER EXAMPLE NAME: unsafe_offsetof

[Name] "unsafe_offsetof"
S1.A: 0
S1.B: 4
S1.C: 8
S1.D: 16
size: 24


[Elapsed] 11.773µs
*/
}