#c #memory #fortran #segmentation-fault
#c #память #fortran #ошибка сегментации
Вопрос:
Я конвертирую программу с fortran77 на язык программирования C, в программе fortran объявляется массив 5D, как показано ниже, и код компилируется и выполняется хорошо. Но когда я преобразую тот же код в C с теми же значениями, код C компилируется, но выдает ошибку сегментации.
Если эта проблема связана с разным стандартным распределением памяти многомерных массивов между двумя языками, я перепробовал все комбинации измерений при объявлении массива на C, и во всех случаях это также дает «ошибку сегментации».
Я также устал от метода ‘calloc’, показанного ниже, и он работает, но я не знаю, как присваивать значения глобально объявленному массиву.
Примечание: ошибка сегментации происходит на этапе объявления (т. Е. Программа останавливается на этом)
Итак, в основном мои вопросы: — Почему это работает на fortran, но не на C?, и, — Как решить эти проблемы на C?
! Fortran77 Code
parameter (i2maxbin=38)
parameter (imaxbin=20)
parameter (Nid=10)
real*8 dNdpt(Nid,i2maxbin,imaxbin,imaxbin,imaxbin)
/* C Code */
const int i2maxbin = 38;
const int imaxbin = 20;
const int nID = 10;
double dNdpt[nID][i2maxbin][imaxbin][imaxbin][imaxbin];
/* Declaring using calloc */
double (*dNdpt)[nID][i2maxbin][imaxbin][imaxbin][imaxbin] =
calloc(sizeof(*dNdpt), 38);
for(int i = 0; i < nID; i )
{
for(int j = 0; j < i2maxbin; j )
{
dNdpt[i][j][0][0][0] = 12.22673423;
}
}
When executing it gives me this error
error: assignment to expression with array type
dNdpt[i][j][0][0][0] = 12.22673423;
^
Комментарии:
1. Код C пытается использовать VLA (массивы переменной длины) — понятия не имею о Fortran. VLA типично реализованы в стеке; и C, как правило, имеет небольшое (иш) пространство стека. Вместо
const int
попытки#define
.2. Невозможно не скомпилировать и выдать segfault. Что происходит?
3. Наиболее вероятная причина заключается в том, что система не позволяет вам использовать много памяти. Его можно изменить (по крайней мере, в GCC), установив некоторые параметры в компиляции. Google (или duckduckgo лучше :)) mcmodel= medium
4. Этот массив будет занимать более 20 МБАЙТ пространства. Локальные нестатические переменные (также известные как автоматические переменные), как обычно, хранятся в (очень ограниченном) стеке. В Windows размер стека по умолчанию для процесса составляет всего один мегабайт, 5% от того, что необходимо для вашего массива.
5. В чем причина ` / * Объявления с использованием calloc */ double (* dNdpt) [nID] [i2maxbin] [imaxbin] [imaxbin] [imaxbin] = calloc(sizeof(* dNdpt), 38);` Вы уже создали переменную, в
double dNdpt[nID][i2maxbin][imaxbin][imaxbin][imaxbin];
которой вам нужно только присвоить значение 0для элементов, 5-уровневый вложенный цикл, для правильной инициализации (если это еще не сделано автоматически).
Ответ №1:
следующий предлагаемый код:
- помещает массив в область действия файла, а не в стек
- чистая компиляция
- позволяет избежать использования динамического выделения / освобождения памяти
- чисто запускается и завершается без сбоев
- позволяет избежать использования VLAS
А теперь предлагаемый код:
#define i2maxbin 38
#define imaxbin 20
#define nID 10
double dNptr[nID][i2maxbin][imaxbin][imaxbin][imaxbin];
int main( void )
{
for(int i = 0; i < nID; i )
{
for(int j = 0; j < i2maxbin; j )
{
dNptr[i][j][0][0][0] = 12.22673423;
}
}
}
Ответ №2:
Размер стека в C, а также в C очень ограничен, как правило, допускается 1D-массив максимального размера 1e5, и если мы примем «двойной» размер равным 8 байтам, то это приведет к максимальной памяти в 8 * 1e5 байт.
Теперь давайте посмотрим на ваш 5D-массив, он пытается выделить 10*38*20*20*20 = 3,040,000 » двойные» единицы измерения, которые при преобразовании в память составляют 24 320 000 байт, что значительно превышает выделенный размер стека в C или C . Вот почему вы получаете ОШИБКУ SEG.
Вы можете попробовать инициализировать массив глобально, чтобы таким образом ему выделялась память кучи, которая обычно больше, чем память стека, даже тогда максимальный размер ограничен 8 * 7 * 1e5 байтами при макс. (зависит от вашей машины).
Комментарии:
1. Речь идет о переменных двойной точности (8 байт), то есть 24 320 000 байт. Размер стека в Windows немного ограничен (но может быть увеличен), в Linux он зависит от настройки ограничения (u). Я не думаю, что 24 МБ слишком велики для стека, но не очень. Вероятно, существует опция компилятора для размещения массивов такого типа в куче.
Ответ №3:
Вы решаете эту проблему, создавая массив в куче вместо стека.
double* dNdpt = malloc(sizeof(double)*nID*i2maxbin*imaxbin*imaxbin*imaxbin);
затем отслеживайте, где вы находитесь в этом гигантском массиве, вычисляя индекс
более простой пример :
double* my2dim = malloc(sizeof(double)*10*20); // 10 rows 20 cols
my2dim[3][2] = 10.0 would be written *(my2dim 3 * 20 2) = 10.0;