C++ и Fortran: ошибка доступа к массивам в общем блоке Fortran из C++

Я пытаюсь получить доступ к массиву в общей блочной структуре Fortran из C++.
У меня есть смешанный пример кода с C++ и Fortran.

Фортран:

integer a(5),b  
common  /sample/ a,b  
a(1) = 1  
a(2) = 5  
a(3) = 10  
a(4) = 15  
a(5) = 20  
b = 25  

Затем в С++:

extern "C"{  
    extern struct{  
        int *a,b;  
}sample_;  

Из С++, если я попытаюсь напечатать значение sample_.b:

printf("sample b:%d\n",sample_.b);

Я получаю значение a(2): sample b:5

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

printf("sample_.a[1]=%d\n",(int)sample_.a[1]);  
printf("sample_.a[0]=%d\n",(int)sample_.a[0]);

Что я делаю не так?¿ Любая идея ¿?
Я думаю, может быть, мне нужно передать длину массива «a» и в C++, но если да, то я тоже не знаю, как это сделать.


person horstmann    schedule 07.05.2012    source источник
comment
Вы не передаете массив коду C++. Вы напрямую обращаетесь к общему блоку как к внешней структуре. Пожалуйста, исправьте свой вопрос соответственно. Я уже поправил заголовок.   -  person Hristo Iliev    schedule 07.05.2012


Ответы (5)


Мой Фортран немного (хорошо, совсем немного) заржавел, но позвольте мне попробовать.

a, вероятно, получил ЗНАЧЕНИЕ, а не указатель на него. Это установит его в 1, что не является хорошим значением указателя.

b получил второе значение в блоке данных. Ваша структура C++ не указывает компилятору, каков реальный формат данных, поэтому он просто бездумно присваивает элементы структуре в порядке, указанном в структуре. Я бы получил указатель на блок данных и разобрал его вручную.

На АДРЕС блока данных назначьте a (похоже на указатель long int; ваш пробег может отличаться) и b = a[5]. Надеюсь, это поможет.

person JoeBuddha    schedule 07.05.2012
comment
ОПС; вероятно, должен быть указатель на int (извините). Если вы присвоите a правильно, a[1] должно быть 5. - person JoeBuddha; 07.05.2012
comment
Близко, он не получает ничего по значению, а скорее в блоке COMMON данные располагаются последовательно и являются непрерывными. По сути, структура C/C++, эквивалентная массивам в блоке COMMON, представляет собой плоский массив. - person user7116; 07.05.2012
comment
Да, если бы это было по стоимости, это было бы по-другому. Он получает адрес блока данных. Я бы по-прежнему разбирал его с помощью целочисленного массива; однако мне лень возиться с сопоставлениями. Кроме того, моя последняя программа на Фортране была написана в 70-х. ;) - person JoeBuddha; 09.05.2012

Если вы хотите совместно использовать глобальные переменные между C и Fortran, лучше всего использовать переменные модуля и Fortran ISO_C_Binding. Общие блоки — это пережиток, которого лучше избегать, если только они не являются частью унаследованного кода. Использование ISO_C_Binding сделает ваш компилятор кода независимым от платформы. Пример кода приведен в подразделе «Взаимодействующие глобальные переменные» главы «Программирование на смешанных языках» руководства по gfortran. Это не относится к gfortran, просто хорошая документация.

Продолжая с ISO_C_Binding, если вы используете типы Fortran, которые он предоставляет, вы будете уверены в совпадении с типами C. Эквивалентом int в языке C на Фортране является C_INT. Список приведен в главе «Внутренние модули» руководства gfortran.

person M. S. B.    schedule 07.05.2012
comment
К сожалению, существуют миллионы строк реликтового кода FORTRAN 77, и не всегда возможно переписать его на Fortran 2003. - person Hristo Iliev; 08.05.2012
comment
Я не согласен с этим, но, э-э, это довольно осторожно отвечает на вопрос Хорстманна. - person user7116; 09.05.2012

Мне кажется, что ваши данные FORTRAN на самом деле представлены как

struct {
  int a[5];
  int b;
}

а ты на машине где sizeof(int) == sizeof(int*).

person Christopher Creutzig    schedule 07.05.2012
comment
+1, члены блока COMMON обычно (не связываясь с параметрами компилятора) последовательно размещаются в памяти. Следовательно, если задан начальный адрес блока COMMON SAMPLE, массив A будет непрерывным с B. - person user7116; 07.05.2012
comment
Следует обратить внимание на выравнивание данных. По умолчанию компиляторы Фортрана не выравнивают элементы блоков COMMON с отступами, но это может измениться, если будут предоставлены агрессивные параметры оптимизации. Следовательно, необходимо убедиться, что структура C/C++ имеет такое же выравнивание своих полей, если на стороне Fortran были использованы оптимизации. - person Hristo Iliev; 07.05.2012

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

integer a(5),b  
common  /sample/ a,b  

a(5) с фиксированным размером, а затем в C++:

extern "C"{  
    extern struct{  
        int *a,b;  
}sample_;  

*a без размера, как указатель. Таким образом, компилятор понимал a таким образом, как указатель *int, а не как массив a(5).

person horstmann    schedule 09.05.2012
comment
Добро пожаловать в StackOverflow! Учитывая, что их ответы решили вашу проблему, вы должны принять Christopher или Ответ Джо. Вы можете сделать это, нажав на галочку рядом с ним. - person user7116; 09.05.2012

Для правильного кода C++/Fortran вы должны использовать по крайней мере Fortran 2003. На самом деле довольно просто создать интерфейс Fortran 2003/2008 для старого кода Fortran (даже для Fortran 77).

Вот ссылка на пост о смешивании современного Fortran и C++:

http://solarianprogrammer.com/2012/05/11/mixed-language-programming-cpp-11-fortran-2008/

person mmisu    schedule 11.05.2012