Добавьте смещение на 64 бита к указателю

В F# существует модуль NativePtr, но это, кажется, только поддерживает смещения на 32 бита для its’, добавлять/получать/функции множества, точно так же, как Система. IntPtr делает.

Существует ли способ добавить смещение на 64 бита к собственному указателю (nativeptr <'a>) в F#? Конечно, я мог преобразовать все адреса в целые числа на 64 бита, сделать нормальные целочисленные операции и затем преобразовать результат снова в nativeptr <'a>, но это будет стоить дополнительный, добавляют и imul инструкции. Я действительно хочу, чтобы AGUs выполнил вычисления адреса.

Например, с помощью небезопасного в C# Вы могли сделать что-то как

void* ptr = Marshal.AllocHGlobal(...).ToPointer();
int64 offset = ...;
T* newAddr = (T*)ptr + offset; // T has to be an unmanaged type

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

В F# мы наконец получили неуправляемое ограничение; но как я делаю адресную арифметику с указателями?

5
задан Frank 24 April 2010 в 16:45
поделиться

2 ответа

Я не эксперт в этой области, но я взглянул на реализацию F # модуля NativePtr и считаю, что преобразование nativeptr <'не влияет на производительность. от a> до nativeint и обратно.

Реализация использует встроенный IL, а встроенный код IL не содержит никакого кода - он нужен только для того, чтобы компилятор F # подумал, что значение в стеке имеет другой тип:

let inline ofNativeInt (x:nativeint)    = (# "" x : nativeptr<_> #)
let inline toNativeInt (x:nativeptr<_>) = (# "" x : nativeint    #)

Фактически, NativePtr.add также использует эти два метода - он преобразует указатель в nativeint , а затем добавляет 32-битное целое число (умноженное на размер типа 'a ).

Итак, следующая функция должна подойти:

let inline addNativeInt (x:nativeptr<'a>) (n:nativeint) : nativeptr<'a> = 
   (NativePtr.toNativeInt x) + n |> NativePtr.ofNativeInt

Все функции, используемые в коде, должны быть встроены, так что вы получите только одну инструкцию для добавления (хотя я не проверял это). Вам даже не нужно беспокоиться об использовании функции несколько раз в коде (вы можете работать с nativeptr <'a> все время и использовать эту функцию для добавления).

Тем не менее, разделение данных также может быть вариантом - насколько мне известно, команда MSR, которая использовала F # для обработки некоторых больших (> 2 ГБ) наборов данных, использовала именно этот подход - они разделили данные на блоки по 2 ГБ (сохраненные в массивах).

3
ответ дан 15 December 2019 в 00:54
поделиться

Данные изображений могут легко превышать 4 Гбайт ;)

Не может, код x64 имеет смещение +/- 2 Гбайт ограничение. Одна из причин, по которой в .NET нельзя выделять массивы размером более 2 ГБ. Это ограничение существует и в неуправляемом 64-битном коде C / C ++. Существуют библиотеки, которые обходят это ограничение, например WIC, но прямая адресация всех битов битовой карты не имеет смысла, когда вы их используете.

Тем не менее, можно сгенерировать такой адрес путем преобразования IntPtr в long в C #:

IntPtr addr = SomeCall();
long offset = blah;
addr = (IntPtr)((long)addr + offset);
1
ответ дан 15 December 2019 в 00:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: