Я пытаюсь преобразовать старый код Fortran 77 в C ++, и большинство переменных объявлены в общих блоках, таких как:
COMMON/BLK1/Gw(200),Eta(4096),t(4096),Phi(200),w(200)
COMMON/BLK2/g,dw,Vel,M,dt,N,Ioutp1,Ioutp2
COMMON/BLK3/Hs,Std,E,Hs1,Tdt
Насколько я понимаю, общие блоки используются просто для того, чтобы сделать переменные доступными по всей программе в различных подпрограммах. Следовательно, смогу ли я создавать в программе на C ++ структуры с переменными (вне основной) и вызывать переменные таким образом как члены структуры?
Основываясь на моем понимании общего эта страница, эквивалент C ++ будет сделать файл с именем common.h
(с включенной защитой), которая содержит:
namespace BLK1
{
int const Gw = 200;
int const Eta = 4096;
int const t = 4096;
int const Phi = 200;
int const w = 200;
}
namespace BLK2
{
extern int g, dw, Vel, M, dt, N, Ioutp1, Ioutp2;
}
namespace BLK3
{
extern int Hs, Std, E, Hs1, Tdt;
}
Кроме того, ровно в одном .cpp
файл в вашем проекте, вы должны предоставить определение для любых неконстант, например, в foo.cpp
:
#include "common.h"
namespace BLK2
{
int g, dw, Vel, M, dt, N, Ioutp1, Ioutp2;
}
namespace BLK3
{
int Hs, Std, E, Hs1, Tdt; // initialized to 0 by default
}
Вы можете использовать другой тип, чем int
например, unsigned long
, Я предполагаю, что инициализированные значения должны быть постоянными; если нет то поменяй int const
в extern int
и удалите инициализатор. Инициализатор должен идти в определении в .cpp
файл.
Избегайте ошибки объявления неконстантной, неэкстерьерной переменной в заголовке; это вызывает неопределенное поведение, если заголовок включен в два разных блока.
Вы получаете доступ к этим переменным, написав BLK1::Eta
например.
Как вы предполагаете, было бы лучше использовать struct
вместо пространства имен, хотя вам все равно придется создать экземпляр структуры, которая объявлена extern
в заголовке и определено ровно в одном .cpp
файл; и если вы до C ++ 11, это более раздражает, чтобы обеспечить инициализаторы.
(Конечно, еще лучше было бы реорганизовать код, чтобы не использовать глобальные переменные. Но это может быть полезно в качестве первого прохода для прямого перевода).
Общие блоки с тем же именем накладываются друг на друга в памяти. Вы можете выделить часть памяти и указатели типов на нее. Другой вариант — объявить их в союзе. Вот почему был изобретен союз. Конечно, когда ваш союз настроен, вы используете extern в других модулях.
Поместите следующее в общий заголовок и его экземпляр в модуль 1.
Добавьте extern, чтобы его можно было увидеть в модуле 2.
union blk1
{
struct module_1_view
{
double gw(200);
double eta(4096);
double t(4096);
double phi(200);
double w(200);
}
struct module_2_view
{
double parameters(8592); // 200 + 4096 + 4096 + 200
double w_status(200);
}
}
Представьте, что модуль 1 отвечает за загрузку некоторого набора двойников из файла в переменные в module_1_view. Как только эти параметры загружены и проверены, вызывается модуль 2, который обращается к параметрам из представления модуля 2. Почти все они доступны через переменную параметров, за исключением w_status, который на самом деле представляет собой 200 индикаторов, которые указывают на успех или проверку параметров.
Ключевым моментом является то, что модули 1 и 2 обращаются к одному и тому же фрагменту памяти (отсюда и к объединению), и они используют свой собственный набор имен переменных.
Я не могу говорить напрямую с Фортраном, но если вы хотите сделать переменную доступной для всей программы на языке c / c ++, extern — это ключевое слово, которое вы ищете.
Extern — это способ обмена данными в стиле C C ++ подтолкнет вас к разработке ОО, в которой переменная, тесно связанная со многими объектами, не является хорошей ОО.
Если вы пытаетесь делать вещи C ++ поверх унаследованного кода, иногда статические методы, которые передаются указателям на ваш класс C ++, могут выступать в качестве оберток. Вот простой пример этого:
extern int _magicVariable;
static void call( void* klass )
{
((MyClass*)klass)->functionCall( _magicVariable );
}
Внутри MyClass вам нужно будет назвать void call (void *) как друга. Теперь унаследованный код может вызывать (void *) с указателем на ваш класс, передавая _magicVariable в ваш OO-дизайн. Оттуда c ++ сделает свое дело.
Суть в том, что у вас есть много способов выполнить задачу, попробуйте сделать то, что имеет смысл, основываясь на желаемой структуре кода.