Отрицательная индексация массива и размещение в памяти (указание)
В Фортране вы можете объявить массив с любым подходящим (целочисленным) диапазоном, например:
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, только проще.