Перейти к основному содержимому

Указатель

Модель явных типов памяти Wave

Дизайн указателей Wave основан на модели явных типов памяти Wave. Модель нацелена на определение указателей и массивов как явных типов памяти на языке, а не как грамматических трюков или библиотечных абстракций.

В соответствии с этой конструкцией в Wave указатели представлены как типы формы ptr<T>, четко указывая, что это тип, указывающий на адрес памяти, хранящий значение конкретного типа T. Этот подход рассматривает указатели как часть системы типов, а не как операторы или грамматику объявлений, что позволяет выразить структуры памяти более интуитивно и последовательно.


В Wave указатели имеют явный тип в форме ptr<T>. Чтобы получить адрес, используется &, а для разыменования — deref.

Объявление и инициализация

var x: i32 = 10;
var p: ptr<i32> = &x;

Тип указателя может быть вложенным.

var p1: ptr<i32> = &x;
var p2: ptr<ptr<i32>> = &p1;

Разыменование

var x: i32 = 10;
var p: ptr<i32> = &x;

println("{}", deref p); // 10
deref p = 20;
println("{}", x); // 20

Правила для литерала null

null — это истинный литерал. Это не идентификатор, и его нельзя использовать в качестве имени переменной.

Основное правило:

  • null можно присваивать только для переменных типа ptr<T>.
  • Нельзя присваивать непоказательным типам таким как i32, bool, array<...>.
  • Указатель не может быть инициализирован целочисленным литералом (0, 123, -1 и др.). Явно использовать null.
var p: ptr<i32> = null;
var arrp: ptr<array<i32, 3>> = null;

// var n: i32 = null; // ERROR
// var b: bool = null; // ERROR

Арифметика указателей

Wave поддерживает следующую арифметику указателей.

  • ptr + int: продвижение указателя на основе GEP
  • ptr + int: идентичное действие
  • int + ptr: обратное движение указателя на основе GEP
  • ptr - int: подсчет разницы в байтах (i64)

Замечание:

  • ptr<T> +/- n перемещается на основе размера типа T (sizeof(T)).
  • То есть ptr<i32> + 3 приведет к перемещению на +12 байт.
var base: ptr<i32> = 0x1000 as ptr<i32>;

var p1: ptr<i32> = base + 3; // 0x1000 + 12
var p2: ptr<i32> = 2 + base; // 0x1000 + 8
var p3: ptr<i32> = base - 1; // 0x1000 - 4

var diff: i64 = p1 - base; // 12 (byte diff)

Сравнение указателей

Указатели могут использоваться для сравнения.

if (p == null) { ... }
if (p != null) { ... }
if (p1 == p2) { ... }

Отношения с массивами

Массив указателей:

var a: i32 = 10;
var b: i32 = 20;
var arr: array<ptr<i32>, 2> = [&a, &b];
println("{} {}", deref arr[0], deref arr[1]);

Указатель на массив:

var p: ptr<array<i32, 3>> = &[1, 2, 3];
if (p != null) {
println("{}", deref p[1]);
}

Примечание по безопасности

Wave в настоящее время не использует модель безопасности указателей с владением/временем жизни как в Rust. Поэтому не гарантируется автоматическая защита от разыменования null. Рекомендуется явно проверять deref перед использованием null.