Spec-Zone.ru › Go

Пакет unsafe

  • import "unsafe"
  • Обзор
  • Индекс

Обзор

Пакет unsafe содержит операции, которые обходят типовую безопасность Go-программ.

Пакеты, импортирующие unsafe, могут быть непереносимыми и не защищены руководящими принципами совместимости Go 1.

Индекс

  • func Alignof(x ArbitraryType) uintptr
  • func Offsetof(x ArbitraryType) uintptr
  • func Sizeof(x ArbitraryType) uintptr
  • func String(ptr *byte, len IntegerType) string
  • func StringData(str string) *byte
  • тип ArbitraryType
  • func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType
  • func SliceData(slice []ArbitraryType) *ArbitraryType
  • тип IntegerType
  • тип Pointer
  • func Add(ptr Pointer, len IntegerType) Pointer

Файлы пакета

unsafe.go

func Alignof

func Alignof(x ArbitraryType) uintptr

Alignof принимает выражение x любого типа и возвращает требуемое выравнивание гипотетической переменной v, как если бы v была объявлена с помощью var v = x. Это наибольшее значение m, такое, что адрес v всегда равен нулю по модулю m. Это то же значение, что и возвращаемое reflect.TypeOf(x).Align(). В качестве специального случая, если переменная s имеет тип struct, а f — поле внутри этой структуры, то Alignof(s.f) вернёт требуемое выравнивание поля этого типа внутри структуры. Этот случай аналогичен значению, возвращаемому reflect.TypeOf(s.f).FieldAlign(). Возвращаемое значение Alignof является Go-константой, если тип аргумента не имеет переменного размера. (См. описание Sizeof для определения типов с переменным размером.)

func Offsetof

func Offsetof(x ArbitraryType) uintptr

Offsetof возвращает смещение внутри структуры поля, представленного x, которое должно иметь вид structValue.field. Другими словами, он возвращает количество байтов между началом структуры и началом поля. Возвращаемое значение Offsetof является Go-константой, если тип аргумента x не имеет переменного размера. (См. описание Sizeof для определения типов с переменным размером.)

func Sizeof

func Sizeof(x ArbitraryType) uintptr

Sizeof принимает выражение x любого типа и возвращает размер в байтах гипотетической переменной v, как если бы v была объявлена с помощью var v = x. Размер не включает память, потенциально ссылающуюся на x. Например, если x — срез, Sizeof возвращает размер описателя среза, а не размер памяти, на которую ссылается срез; если x — интерфейс, Sizeof возвращает размер значения интерфейса, а не размер значения, хранящегося в интерфейсе. Для структуры размер включает любой дополнительный байт, введённый выравниванием поля. Возвращаемое значение Sizeof является Go-константой, если тип аргумента x не имеет переменного размера. (Тип имеет переменный размер, если это параметр типа или это массив или структура с элементами переменного размера.)

func String

func String(ptr *byte, len IntegerType) string

String возвращает строковое значение, лежащие байты которого начинаются в ptr, а длина равна len.

Аргумент len должен быть целого типа или нетипированной константой. Аргумент len-константа должен быть неотрицательным и представимым значением типа int; если это нетипированная константа, ей присваивается тип int. Во время выполнения, если len отрицательное, или если ptr равен nil, а len не равно нулю, происходит паника во время выполнения.

Поскольку Go-строки неизменяемы, байты, переданные в String, не должны изменяться, пока существует возвращаемое строковое значение.

func StringData

func StringData(str string) *byte

StringData возвращает указатель на лежащие байты str. Для пустой строки возвращаемое значение не определено и может быть nil.

Поскольку Go-строки неизменяемы, байты, возвращаемые StringData, не должны изменяться.

тип ArbitraryType

ArbitraryType здесь только для целей документации и не является фактической частью пакета unsafe. Он представляет тип произвольного Go-выражения.

type ArbitraryType int

func Slice

func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType

Функция Slice возвращает срез, подлежащий массив которого начинается в ptr, а длина и ёмкость которых равны len. Slice(ptr, len) эквивалентен

(*[len]ArbitraryType)(unsafe.Pointer(ptr))[:]

за исключением того, что, в качестве специального случая, если ptr равен nil и len равен нулю, Slice возвращает nil.

Аргумент len должен быть целого типа или нетипированной константой. Аргумент len-константа должен быть неотрицательным и представимым значением типа int; если это нетипированная константа, ей присваивается тип int. Во время выполнения, если len отрицательное, или если ptr равен nil, а len не равно нулю, происходит паника во время выполнения.

func SliceData

func SliceData(slice []ArbitraryType) *ArbitraryType

SliceData возвращает указатель на подлежащий массив аргумента slice.

  • Если cap(slice) > 0, SliceData возвращает &slice[:1][0].
  • Если slice == nil, SliceData возвращает nil.
  • В противном случае SliceData возвращает не-nil указатель на неопределённый адрес памяти.

тип IntegerType

IntegerType здесь только для целей документации и не является фактической частью пакета unsafe. Он представляет любой произвольный целочисленный тип.

type IntegerType int

тип Pointer

Pointer представляет указатель на произвольный тип. Есть четыре специальные операции, доступные для типа Pointer, которые недоступны для других типов:

  • Значение указателя любого типа может быть преобразовано в Pointer.
  • Pointer может быть преобразован в значение указателя любого типа.
  • uintptr может быть преобразован в Pointer.
  • Pointer может быть преобразован в uintptr.

Поэтому Pointer позволяет программе обойти систему типов и читать и записывать произвольную память. Его следует использовать с большой осторожностью.

Следующие шаблоны, связанные с Pointer, являются допустимыми. Код, не использующий эти шаблоны, вероятно, недействителен сегодня или станет недействительным в будущем. Даже допустимые шаблоны ниже имеют важные замечания.

(1) Преобразование *T1 в Pointer в *T2.

При условии, что T2 не больше T1 и что оба имеют эквивалентную структуру памяти, это преобразование позволяет переинтерпретировать данные одного типа как данные другого типа. Примером является реализация math.Float64bits:

func Float64bits(f float64) uint64 {
	return *(*uint64)(unsafe.Pointer(&f))
}

(2) Преобразование Pointer в uintptr (но не обратно в Pointer).

Преобразование Pointer в uintptr даёт адрес значения, на которое указывает указатель, как целое число. Обычно такой uintptr используется для его вывода.

Преобразование uintptr обратно в Pointer не является допустимым в общем случае.

uintptr — это целое число, а не ссылка. Преобразование Pointer в uintptr создаёт целочисленное значение без семантики указателя. Даже если uintptr содержит адрес некоторого объекта, сборщик мусора не будет обновлять значение uintptr, если объект перемещается, и этот uintptr не удерживает объект от возвращения.

Остальные шаблоны перечисляют единственные допустимые преобразования из uintptr в Pointer.

(3) Преобразование Pointer в uintptr и обратно с арифметикой.

Если p указывает на выделенный объект, его можно продвинуть через объект преобразованием в uintptr, добавлением смещения и преобразованием обратно в Pointer.

p = unsafe.Pointer(uintptr(p) + offset)

Наиболее распространённое использование этого шаблона — доступ к полям в структуре или элементам массива:

// equivalent to f := unsafe.Pointer(&s.f)
f := unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f))

// equivalent to e := unsafe.Pointer(&x[i])
e := unsafe.Pointer(uintptr(unsafe.Pointer(&x[0])) + i*unsafe.Sizeof(x[0]))

Допустимо как добавлять, так и вычитать смещения от указателя таким образом. Также допустимо использовать &^ для округления указателей, обычно для выравнивания. Во всех случаях результат должен продолжать указывать на исходный выделенный объект.

В отличие от C, не допускается продвижение указателя сразу за пределы конца его исходного выделения:

// INVALID: end points outside allocated space.
var s thing
end = unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + unsafe.Sizeof(s))

// INVALID: end points outside allocated space.
b := make([]byte, n)
end = unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(n))

Обратите внимание, что оба преобразования должны появляться в одном выражении, при этом только интервал арифметики между ними:

// INVALID: uintptr cannot be stored in variable
// before conversion back to Pointer.
u := uintptr(p)
p = unsafe.Pointer(u + offset)

Обратите внимание, что указатель должен указывать на выделенный объект, поэтому он не может быть nil.

// INVALID: conversion of nil pointer
u := unsafe.Pointer(nil)
p := unsafe.Pointer(uintptr(u) + offset)

(4) Преобразование Pointer в uintptr при вызове функций, таких как syscall.Syscall.

Функции Syscall в пакете syscall передают свои аргументы uintptr непосредственно операционной системе, которая затем, в зависимости от подробностей вызова, может переинтерпретировать некоторые из них как указатели. То есть, реализация системного вызова неявно преобразует некоторые аргументы обратно из uintptr в указатель.

Если аргумент указателя должен быть преобразован в uintptr для использования в качестве аргумента, это преобразование должно появляться в выражении вызова:

syscall.Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(n))

Компилятор обрабатывает Pointer, преобразованный в uintptr в списке аргументов вызова функции, реализованной в сборке, организуя сохранение и недопустимость перемещения выделенного объекта, если таковой имеется, до завершения вызова, даже если из одних типов видно, что объект больше не нужен во время вызова.

Для распознавания этого шаблона компилятором преобразование должно появляться в списке аргументов:

// INVALID: uintptr cannot be stored in variable
// before implicit conversion back to Pointer during system call.
u := uintptr(unsafe.Pointer(p))
syscall.Syscall(SYS_READ, uintptr(fd), u, uintptr(n))

(5) Преобразование результата reflect.Value.Pointer или reflect.Value.UnsafeAddr из uintptr в Pointer.

Методы Value пакета reflect, имеющие названия Pointer и UnsafeAddr, возвращают тип uintptr вместо unsafe.Pointer, чтобы предотвратить изменение результата на произвольный тип без предварительного импорта «unsafe». Однако это означает, что результат хрупкий и должен быть преобразован в Pointer сразу после вызова, в одном выражении:

p := (*int)(unsafe.Pointer(reflect.ValueOf(new(int)).Pointer()))

Как и в предыдущих случаях, хранение результата перед преобразованием недопустимо:

// INVALID: uintptr cannot be stored in variable
// before conversion back to Pointer.
u := reflect.ValueOf(new(int)).Pointer()
p := (*int)(unsafe.Pointer(u))

(6) Преобразование поля reflect.SliceHeader или reflect.StringHeader Data в Pointer или из него.

Как и в предыдущем случае, структуры данных reflect SliceHeader и StringHeader объявляют поле Data как uintptr, чтобы предотвратить изменение результата на произвольный тип без предварительного импорта «unsafe». Однако это означает, что SliceHeader и StringHeader допустимы только при интерпретации содержимого фактического среза или строки.

var s string
hdr := (*reflect.StringHeader)(unsafe.Pointer(&s)) // case 1
hdr.Data = uintptr(unsafe.Pointer(p))              // case 6 (this case)
hdr.Len = n

В этом использовании hdr.Data фактически является альтернативным способом ссылки на подлежащий указатель в заголовке строки, а не на переменную uintptr сама по себе.

В общем случае reflect.SliceHeader и reflect.StringHeader должны использоваться только как *reflect.SliceHeader и *reflect.StringHeader, указывающие на фактические срезы или строки, никогда как простые структуры. Программа не должна объявлять или выделять переменные этих типов структур.

// INVALID: a directly-declared header will not hold Data as a reference.
var hdr reflect.StringHeader
hdr.Data = uintptr(unsafe.Pointer(p))
hdr.Len = n
s := *(*string)(unsafe.Pointer(&hdr)) // p possibly already lost
type Pointer *ArbitraryType

func Add

func Add(ptr Pointer, len IntegerType) Pointer

Функция Add добавляет len к ptr и возвращает обновлённый указатель Pointer(uintptr(ptr) + uintptr(len)). Аргумент len должен быть целого типа или нетипированной константой. Аргумент len-константа должна быть представимой значением типа int; если это нетипированная константа, ей присваивается тип int. Правила для допустимых использования Pointer всё ещё применяются.

© Google, Inc.
Licensed under the Creative Commons Attribution License 3.0.
http://golang.org/pkg/unsafe/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API