Отрицательная индексация массива и размещение в памяти (указание)

В Фортране вы можете объявить массив с любым подходящим (целочисленным) диапазоном, например:

real* 8 array(-10:10)

Я считаю, что fortran при передаче по ссылке всегда будет передавать массив (1) в качестве ссылки, но я не уверен.

Я использую указатели фортрана, и я считаю, что фортран указывает на "1-й" адрес элемента, т.е. массив (1), а не массив (-10). Однако я не уверен.

Как Fortran справляется с отрицательной индексацией массива в памяти? И определяется ли имплиментация?

Изменить: Чтобы добавить немного больше деталей, я передаю блок malloc от C к Fortran с помощью указателя Fortran, чтобы указать на адрес, что делается путем вызова процедуры Fortran из CIe C:

void * pointer = malloc(blockSize*sizeof(double));
fortranpoint_(pointer);

И рутина точки Фортрана выглядит так:

real*8 :: target block(5, -6:6, 0:0)
real*8 :: pointer array(:,:,:)

entry fortranPoint(block)
array => block
return

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

array(1, -6, 0)

Я не уверен, что это доступ к адресу в начале блока или где-то до него. Теперь я думаю, что это определяется реализацией, но хотел бы узнать подробности каждой реализации.

2 ответа

Решение

Аргумент массива Fortran ABI зависит от компилятора и, что более важно, от того, имеет ли вызываемая процедура явный или неявный интерфейс.

Для неявного интерфейса обычно передается адрес первого элемента [1]. В вызываемом вызове процедура добавляет смещение в зависимости от того, как объявлен фиктивный аргумент массива. Например, если фиктивный аргумент массива объявлен somearray(-10:10), то ссылка на somearray(x) вычисляется как

address_of_first_element_passed_in_to_the_procedure + x + 10

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

[1] Обратите внимание, что это первый элемент в памяти, то есть самый низкий индекс для каждого измерения. Не somearray(1) независимо от того, как массив был объявлен.

Чтобы ответить на ваш обновленный вопрос, для взаимодействия C/Fortran, используйте функцию ISO_C_BINDING, которая в настоящее время широко доступна. Это обеспечивает стандартизированный способ передачи информации между C и Fortran.

Если фиктивный аргумент для обычного массива в Fortran объявлен A(:) (или с большим количеством измерений), передается SHAPE, а не конкретный диапазон индекса. Таким образом, процедура по умолчанию будет одноиндексной. Вы можете переопределить это с помощью объявления в процедуре A(-10:) или A(StartIndex:), где StartIndex - еще один аргумент.

Указатели Fortran включают диапазон индекса, но механизм передачи будет зависеть от компилятора. Код, взаимодействующий с C, вероятно, зависит от ОС и компилятора. Как уже предлагалось, я бы использовал обычный массив и привязку ISO C. Это НАМНОГО проще, чем старые способы выяснения механизмов передачи компилятора и стандартные и переносимые. Если у вас большой существующий код на Фортране, вы можете написать "склеивающую" процедуру на Фортране, которая сопоставляет обычные объявления переменных на Фортране и имена привязок ISO C. Хотя их типы будут иметь формально разные имена, на практике они будут одинаковыми, если вы выберете правильные типы ISO C. Привязка ISO C доступна уже много лет. Можете ли вы обновить компилятор на целевой целевой платформе? Если нет, я бы использовал обычный массив Фортрана и либо использовал бы нулевое индексирование на стороне C, либо явно передавал в качестве аргументов нужные индексы.

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

Интерфейс к процедуре является явным, если он объявлен так, что он известен компилятору в вызывающей программе. Самый простой способ - разместить процедуры в модуле и "использовать" модуль в вызывающей программе. Наличие явных интерфейсов помогает избежать ошибок, поскольку компилятор может проверять согласованность между аргументами вызывающего и вызываемого. Это немного похоже на заголовочные файлы C, только проще.

Другие вопросы по тегам