Функция unsafe.Offsetof
Функция unsafe.Offsetof возвращает смещение (offset) поля структуры в байтах относительно начала этой структуры. Она принимает один параметр - выражение вида struct.Field, где struct - это переменная или значение структуры, а Field - имя поля, смещение которого нужно получить. Функция возвращает значение типа uintptr, представляющее смещение поля в байтах.
Функция unsafe.Offsetof полезна при работе с низкоуровневыми операциями, такими как сериализация данных, работа с бинарными протоколами или прямое взаимодействие с памятью. Важно помнить, что смещение поля может зависеть от архитектуры компьютера и выравнивания данных, поэтому результаты могут отличаться на разных платформах.
Синтаксис
unsafe.Offsetof(struct.Field)
Пример
Давайте получим смещение полей структуры Person:
package main
import (
"fmt"
"unsafe"
)
type Person struct {
Name string
Age int
City string
}
func main() {
var p Person
nameOffset := unsafe.Offsetof(p.Name)
ageOffset := unsafe.Offsetof(p.Age)
cityOffset := unsafe.Offsetof(p.City)
fmt.Printf("Name offset: %d\n", nameOffset)
fmt.Printf("Age offset: %d\n", ageOffset)
fmt.Printf("City offset: %d\n", cityOffset)
}
Результат выполнения кода:
"Name offset: 0"
"Age offset: 16"
"City offset: 24"
Пример
Используем unsafe.Offsetof для получения смещения полей структуры с различными типами данных:
package main
import (
"fmt"
"unsafe"
)
type Data struct {
A bool
B int64
C float64
D byte
}
func main() {
var d Data
offsetA := unsafe.Offsetof(d.A)
offsetB := unsafe.Offsetof(d.B)
offsetC := unsafe.Offsetof(d.C)
offsetD := unsafe.Offsetof(d.D)
fmt.Printf("Offset of A (bool): %d\n", offsetA)
fmt.Printf("Offset of B (int64): %d\n", offsetB)
fmt.Printf("Offset of C (float64): %d\n", offsetC)
fmt.Printf("Offset of D (byte): %d\n", offsetD)
}
Результат выполнения кода:
"Offset of A (bool): 0"
"Offset of B (int64): 8"
"Offset of C (float64): 16"
"Offset of D (byte): 24"
Пример
Используем unsafe.Offsetof вместе с unsafe.Pointer для прямого доступа к полям структуры по их смещению:
package main
import (
"fmt"
"unsafe"
)
type User struct {
ID int
Name string
}
func main() {
user := User{ID: 42, Name: "Alice"}
// Получаем смещение поля Name
nameOffset := unsafe.Offsetof(user.Name)
// Получаем указатель на структуру
ptr := unsafe.Pointer(&user)
// Вычисляем указатель на поле Name
namePtr := unsafe.Pointer(uintptr(ptr) + nameOffset)
// Читаем значение поля Name через указатель
name := *(*string)(namePtr)
fmt.Printf("Name field value: %s\n", name)
// Изменяем значение поля Name
*(*string)(namePtr) = "Bob"
fmt.Printf("Modified user: %+v\n", user)
}
Результат выполнения кода:
"Name field value: Alice"
"Modified user: {ID:42 Name:Bob}"
Смотрите также
-
функцию
unsafe.Sizeof,
которая возвращает размер значения в байтах -
функцию
unsafe.Alignof,
которая возвращает выравнивание значения -
функцию
unsafe.Pointer,
которая представляет указатель произвольного типа -
функцию
unsafe.Add,
которая выполняет арифметику указателей