Существует ли в Go адресная арифметика?

Ответ

В Go, в его безопасной части, нет адресной арифметики, в отличие от C/C++. Указатели в Go спроектированы быть безопасными: они могут быть nil или указывать на действительный объект в памяти, но с ними нельзя производить арифметические операции (например, ptr++).

Однако для низкоуровневых операций, где требуется прямой доступ к памяти, существует пакет unsafe.

Пакет unsafe

Он позволяет обойти систему типов Go. С его помощью можно преобразовать указатель в тип uintptr (целочисленный тип, достаточный для хранения адреса), выполнить над ним арифметические операции, а затем преобразовать обратно в unsafe.Pointer.

Пример:

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    arr := [3]int{10, 20, 30}

    // Получаем указатель на первый элемент
    p := &arr[0]

    // Преобразуем в unsafe.Pointer, затем в uintptr для арифметики
    // uintptr - это просто число, а не указатель
    addr := uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(arr[0])

    // Преобразуем адрес обратно в типизированный указатель
    nextP := (*int)(unsafe.Pointer(addr))

    fmt.Println(*nextP) // Выведет: 20
}

Важно: Использование unsafe ломает гарантии безопасности типов и памяти в Go и может привести к непредсказуемому поведению или панике. Его следует применять только в исключительных случаях, например:

  • Для критической оптимизации производительности.
  • При взаимодействии с кодом на C через Cgo.
  • При реализации очень низкоуровневых структур данных.

В подавляющем большинстве случаев следует использовать безопасные альтернативы, такие как срезы (slices).

Ответ 18+ 🔞

А, слушай, вот это интересный момент, про который многие, блядь, с порога заблуждаются! В Go, в его нормальном, штатном режиме — адресной арифметики нихуя нету, в отличие от этих твоих C/C++, где можно по памяти шастать как по своему огороду.

Указатели в Go — они как воспитанные дети: либо nil (ни на что не указывают), либо тыкаются в конкретный, законный объект. Сказать им ptr++, чтобы перепрыгнуть на соседнюю память — нихуя не выйдет, компилятор тебя по рукам нахуй даст.

Но, как и в любой строгой системе, блядь, есть чёрный ход. Для тех, кто готов, сука, на всё ради скорости или чтобы с легаси-кодом подружиться — есть пакет unsafe.

Пакет unsafe — откровенный гопник в мире типов

Этот пакет — он как отмычка. Позволяет, сука, обойти всю эту политкорректную систему типов Go. Алгоритм простой, как три копейки:

  1. Берёшь свой типизированный указатель, превращаешь его в unsafe.Pointer (это такая серая, бестиповая хуйня).
  2. А потом — о, магия! — конвертируешь это в uintptr. Это уже просто число, ёпта, адрес в памяти. И вот с этим числом можно делать что угорячишь: прибавлять, вычитать — классическая арифметика, блядь.
  3. А потом, сука, обратно собираешь: uintptr -> unsafe.Pointer -> в нужный тебе тип указателя.

Смотри, как это выглядит в деле:

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    arr := [3]int{10, 20, 30}

    // Ловим указатель на первый элемент
    p := &arr[0]

    // Начинается магия, блядь:
    // 1. Указатель -> в бестиповый unsafe.Pointer
    // 2. unsafe.Pointer -> в голый адрес (uintptr)
    // 3. К адресу прибавляем размер одного int'а
    addr := uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(arr[0])

    // А теперь собираем всё обратно, в рот меня чих-пых!
    // 1. Адрес (uintptr) -> обратно в unsafe.Pointer
    // 2. unsafe.Pointer -> в указатель на int (*int)
    nextP := (*int)(unsafe.Pointer(addr))

    fmt.Println(*nextP) // Выведет, ясное дело, 20
}

Но запомни раз и нахуй: использование unsafe — это как снять все предохранители. Гарантии безопасности памяти и типов летят в пизду. Можешь запросто наступить на грабли и получить панику, или, что хуже, тихие, ебучие corruption данных.

Применять эту темную магию стоит только в крайних случаях, когда уже припёрло:

  • Для дикой, запредельной оптимизации, где каждый наносекунд на счету.
  • Когда через Cgo общаешься с каким-нибудь древним С-шным кодом, который тебе, как проклятие, достался.
  • Когда пишешь свою хитровыебанную, низкоуровневую структуру данных.

А так-то, в 99.9% случаев, тебе должно хватать нормальных, человеческих срезов (slices). Не лезь туда, куда не просят, а то мало не покажется!