Доступ к общему блоку Fortran из C как структура - PullRequest
0 голосов
/ 26 марта 2019

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

Ограничения: использование 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()

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

Метод в CVFortran Manual:

Fortran

      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. Это не дает ошибок, но возвращает нулевые значения для всех моих переменных.

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

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

C функция


#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

Ответы [ 2 ]

1 голос
/ 26 марта 2019

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

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

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

extern rtype really_;

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

rtype really_;

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

Более того, неясно, почему вы ожидаете получить доступ к общему блоку Fortran REALLY через имя really_. Ни конкретный пример, представленный вами в документации по CVF, ни более широкий текст этих документов не подтверждают этот вывод. Поскольку псевдоним этого блока, объявленного на стороне Фортрана, отсутствует, документы заставляют меня ожидать, что к нему будет открыт доступ на стороне 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 также, по-видимому, предполагают, что не манипулирует внешними именами объектов Фортрана, украшая их подчеркиванием. (Я недостаточно прочел, чтобы определить, применимо ли это к подпрограммам и функциям.)
  • Несмотря на то, что это не так, необязательно typedef тип структуры для общего блока. Однако, учитывая характер данных, мне кажется более естественным , чем .
  • Обратите внимание, что мой пример кода C предоставляет только объявление для объекта REALLY (как внешний объект), а не определение.
  • При желании вы можете переместить объявление REALLY в заголовочный файл. Это было бы уместно, если вы собираетесь получать к нему доступ из нескольких модулей перевода C, но не нужно, если вы собираетесь использовать его только в одном.
  • Вы также можете поместить объявление своей функции в заголовочный файл, но это служит цели, только если она вызывается другими функциями C, определенными в других единицах перевода.
0 голосов
/ 26 марта 2019

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

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

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

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

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

...