Доступ к общему блоку Fortran из C как к структуре

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

Ограничения: Использование cvfortran, f77. Конвертировать в более новые форматы не реально. Для C используется компилятор MSVS C.

Вот предложение из руководства cvfortran, стр. 618: (http://jp.xlsoft.com/documents/intel/cvf/cvf_pg.pdf)

«В качестве примера предположим, что ваш код на Фортране имеет общий блок с именем Really, как показано ниже:»

!DEC$ ATTRIBUTES ALIAS:'Really' :: Really
REAL(4) x, y, z(6)
REAL(8) ydbl
COMMON / Really / x, y, z(6), ydbl

«Вы можете получить доступ к этой структуре данных из своего кода C со следующей внешней структурой данных:»

#pragma pack(2)
extern struct {
float x, y, z[6];
double ydbl;
} Really;
#pragma pack()

Всякий раз, когда я пытаюсь это сделать, я получаю сообщение об ошибке «Неразрешенный внешний символ, действительно указанный в функции xxx, и он не компилируется.

Метод в CVFortran Manual:

Фортран

      PROGRAM MYPROG
      !DEC$ ATTRIBUTES ALIAS:'Really' :: Really
      REAL(4) x, y, z
      COMMON / Really / x, y, z

      INTERFACE 
          SUBROUTINE STRUCTFUN()
cDEC$ ATTRIBUTES C, ALIAS:'_StructFun' :: STRUCTFUN  ! for calling C functions
          END SUBROUTINE STRUCTFUN 
      END INTERFACE  
      X = 6.
      Y = 5.
      Z = 0.       

      CALL STRUCTFUN() 
      END PROGRAM

C

#include <stdio.h>

void StructFun(void)
{
    #pragma pack(2)
    extern struct {
    float x, y, z;
    } Really;
    #pragma pack()
    printf("x: %f\n y: %f\n z: %f\n", Really.x, Really.y, Really.z);
    printf("From C \n");

}

Затем я попробовал то, что я вставил ниже, в котором я определяю тип структуры в заголовочном файле, а затем пытаюсь сделать его внешним по отношению к c. Я также должен упомянуть, что я экспортирую функцию C как dll с файлом .def, чтобы ее можно было вызывать из моего модуля fortran. Это не дает ошибок, но возвращает нулевые значения для всех моих переменных.

Пример программы:

Фортран

      PROGRAM MYPROG
      REAL(4) X,Y,Z
      COMMON / REALLY / X, Y, Z

      INTERFACE 
          SUBROUTINE STRUCTFUN()
cDEC$ ATTRIBUTES C, ALIAS:'_StructFun' :: STRUCTFUN  ! for calling C functions
          END SUBROUTINE STRUCTFUN 
      END INTERFACE  
      X = 6.
      Y = 5.
      Z = 0.       

      CALL STRUCTFUN() 
      END PROGRAM

С-функция


#include "structProg.h"
rtype really_;
void StructFun(void)
{
  printf("x: %f\n y: %f\n z: %f\n", really_.x, really_.y, really_.z);
  printf("From C \n");

}

Заголовочный файл C

#include <string.h>
#include <stdio.h>

typedef struct{
    float x;
    float y;
    float z;
} rtype;

extern rtype really_;
extern void StructFun(void);

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

Я также пробовал метод, указанный здесь: http://www.yolinux.com/TUTORIALS/LinuxTutorialMixingFortranAndC.html


person DHarry    schedule 26.03.2019    source источник
comment
Сообщение об ошибке, о котором вы сообщаете, не соответствует коду, который вы представляете. В частности, внешний символ, на который он жалуется, — это _Really, но ни один из ваших кодов не ссылается на такой символ и не обращается к нему. Более того, хотя ваш код C обращается к похожему символу really_, он также предоставляет определение этого символа и поэтому не должен вызывать такую ​​ошибку. Нам будет достаточно трудно помочь вам со старой и несколько своеобразной цепочкой инструментов, которую вы используете, поэтому для вас еще важнее, чем обычно, представить минимальный воспроизводимый пример, который действительно демонстрирует проблему.   -  person John Bollinger    schedule 26.03.2019
comment
Я отредактирую пример первого примера, извините за это.   -  person DHarry    schedule 26.03.2019
comment
Ваш код не совместим с FORTRAN 77. REAL(4) - это синтаксис Fortran 90, а число 4 не совпадает с 4, как в REAL*4 stackoverflow.com/questions/838310/fortran-90-kind-parameter Ключевое слово INTERFACE также является Fortran 90+.   -  person Vladimir F    schedule 26.03.2019
comment
Я не уверен в первом комментарии, но быстрый поиск в Google показывает примеры использования F77 блоков INTERFACE. После изменения типа жалобы у меня те же результаты.   -  person DHarry    schedule 26.03.2019
comment
Вы имеете в виду программы, которые для вас выглядят как F77... ИНТЕРФЕЙС - это определенно Fortran 90. Вы можете проверить стандарт, связанный на странице тегов stackoverflow. com/tags/fortran/info Compaq Visual Fotran поддерживает Fortran 90, и расширение файла .f или .f90 не имеет для этого никакого значения, оно только определяет форму исходного кода fiexd и free.   -  person Vladimir F    schedule 26.03.2019


Ответы (2)


Ваш обновленный вопрос представляет собой проблему, отличную от исходной. Теперь проблема в следующем:

Это не дает ошибок, но возвращает нулевые значения для всех моих переменных.

Это потому, что вы вообще не обращаетесь к общему блоку. Несмотря на внешнее объявление объекта really_ в вашем заголовочном файле...

extern rtype really_;

... ваш исходный файл .c содержит определение объекта really_ из-за этого:

rtype really_;

Технически это «предварительное определение», но в той же единице трансляции нет определения с инициализатором, назначенный объект определяется в этой TU и инициализируется со всеми членами 0. Поэтому неудивительно, что ваш код C распечатывает эти нули.

Кроме того, неясно, почему вы ожидаете получить доступ к общему блоку Фортрана REALLY через имя really_. Ни конкретный пример, который вы представили из документов CVF, ни более широкий текст этих документов не подтверждают этот вывод. Поскольку псевдоним для этого блока, объявленного на стороне Fortran, отсутствует, документы позволяют мне ожидать, что доступ к нему будет осуществляться на стороне C через полностью заглавную версию его имени, REALLY:

extern struct {
    float x;
    float y;
    float z;
} REALLY;

void StructFun(void) {
    printf("x: %f\n y: %f\n z: %f\n", REALLY.x, REALLY.y, REALLY.z);
    printf("From C \n");
}

Обратите внимание, в частности, что

  • C чувствителен к регистру, тогда как Fortran - нет, но документы CVF, кажется, указывают, что по умолчанию он создает внешние имена в верхнем регистре для объектов и функций Fortran.
  • В документах CVF также предполагается, что он не искажает внешние имена объектов Fortran, украшая их символами подчеркивания. (Я не читал достаточно, чтобы определить, применимо ли то же самое к подпрограммам и функциям.)
  • Хотя в этом нет ничего плохого, нет необходимости использовать typedef тип структуры для общего блока. Однако, учитывая характер данных, мне кажется более естественным не этого делать.
  • Обратите внимание, что мой пример кода C предоставляет только декларацию для объекта REALLY (как внешнего объекта), а не определение.
  • При желании вы можете переместить объявление REALLY в заголовочный файл. Это было бы уместно, если вы собираетесь обращаться к нему из нескольких единиц перевода C, но не нужно, если вы собираетесь использовать его только в одной.
  • Вы также можете поместить объявление своей функции в заголовочный файл, но это служит цели, только если она вызывается другими функциями C, определенными в других единицах перевода.
person John Bollinger    schedule 26.03.2019

Я здесь не гуру, но ошибка свидетельствует о том, что нет интегрированной программы "C и Fortran".

Вы разрабатываете некоторые модули на Fortran и некоторые модули на C (C++). Вы решаете, будет ли это программа на C (и тогда она будет иметь main в качестве точки входа в программу) или программа на Fortran (и тогда она будет иметь точку входа в программу на Fortran).

Вы компилируете модули C и модули Fortran с помощью соответствующих компиляторов. Они доставляют файлы .obj или .o, объектные файлы. Наконец, вы связываете их вместе, чтобы создать исполняемую программу.

То, что вы сделали, кажется правильным. Но ошибка «Неразрешенный внешний символ» — это ошибка компоновщика. Это означает, что компоновщик не смог найти блок Fortran Common в объектных модулях.

Надеюсь, это поможет.

person Paul Ogilvie    schedule 26.03.2019
comment
Я думал, что вопросы с этими ошибками должны быть просто закрыты meta.stackoverflow .com/questions/381483/ - person Vladimir F; 26.03.2019
comment
Так что в случае с неразрешенным внешним символом мне нужно будет сначала скомпилировать фортран, а затем связать объектные файлы с исходным кодом C? Я пытался скомпилировать исходный код C, экспортировать в dll и связать его библиотеку импорта с исходным файлом fortran вместе с компилятором fortran. - person DHarry; 26.03.2019
comment
Экспорт в DLL — это совсем другое, чем связывание объектов, созданных Fortran и C, в один исполняемый файл! - person Paul Ogilvie; 27.03.2019