Использование глобальных многомерных массивов

В настоящее время я работаю над аппаратным проектом на основе Atmega2560, и я написал около 2000 строк кода C ++, который теперь становится неуправляемым. Это проект для местного сообщества, и ремонтопригодность важна, поэтому я пытаюсь разложить все по модулям и упростить, чтобы кто-то с еще меньшим пониманием C ++, который у меня был, мог хотя бы понять, что происходит.

В основе проекта лежит глобальный многомерный целочисленный массив, изначально объявленный в main.cpp (где он отлично работал со всеми функциями, содержащимися в main.cpp):

// main.cpp
const int A = 30;
const int B = 20;
const int C = 10;
int gArray[A][B][C];

Если я сделаю то же самое с GLOBAL.h, он будет компилироваться нормально - так что, очевидно, A, B и C принимаются как константы. Но это не работает с модулями. Если в модуле кода я использую:

// setup.cpp
extern const int A;
extern const int B;
extern const int C;

extern int gArray[A][B][C];

Я получаю, что граница массива не является целочисленной константой до ошибки токена ']'.

Итак, мой вопрос в основном - как я могу использовать глобальный многомерный массив в нескольких модулях с фиксированными размерами, установленными в одном месте для удобства обслуживания?

Я пытался кое-что отсортировать, читал и пробовал много идей, которые я читал, но мне не удалось добиться какого-либо прогресса. Тем временем я создал функции для установки и чтения значений массива и поместил их в GLOBALS.h - что кажется неэлегантным, но представляет собой понятный и практичный обходной путь:

const int A=30;
const int B=20;
const int C=10;

int gARRAY[A][B][C];

void setARRAY(int A, int B, int C, int V) {
    gARRAY[A][B][C] = V;   
}

int getARRAY(int A, int B, int C) {    
    return gARRAY[A][B][C];
}

person Gotty    schedule 15.10.2020    source источник
comment
Вы должны добавить extern к константным переменным во всех файлах. Где вы их декларируете и где используете.   -  person Emmanuel Mathi-Amorim    schedule 15.10.2020
comment
@ EmmanuelMathi-Amorim Я не уверен, что только это сработает. Компилятор жалуется, потому что у него нет значений A, B, C, где массив объявлен extern.   -  person Anonymous1847    schedule 16.10.2020
comment
@ Anonymous1847 Я понимаю, о чем вы. OP, вероятно, должен переключить переменные const на определения макросов или, если у них есть доступный C ++ constexpr, то это лучше всего.   -  person Emmanuel Mathi-Amorim    schedule 16.10.2020


Ответы (3)


РЕШЕНО !!!

Во-первых, моя вина - следуя советам с использованием gArray[30][20][10], я не заметил, что я превысил объем ОЗУ !! Итак, когда у меня могло быть то, что должно было быть рабочим методом, процессор вылетал [без предупреждений компилятора]. На самом деле мне нужно только gArray[10][13][10]

В результате исправления этого и использования советов из добрых комментариев все заработало.

Если кому-то еще нужно использовать глобальные многомерные массивы, вот как я это сделал [обратите внимание, что я использую среду Arduino, поэтому нет int main(), например]:

Сначала в GLOBALS.h я установил размеры #defines, а затем объявил массив в GLOBALS.cpp:

// --- GLOBALS.h -------------------------
#ifndef GLOBALS_H
#define GLOBALS_H

    #define A 10
    #define B 13
    #define C 10

#endif

// --- GLOBALS.cpp -----------------------------
#include "GLOBALS.h"

int gArray[A][B][C];

Затем я создал пару тестовых модулей setup.h & setup.cpp для инициализации значений массива и testaccess.h & testaccess.cpp для изменения значений, а также main.cpp для его проверки [содержащие Arduino void setup() и void loop(), последний не отображается, поскольку он пустой]:

//--- setup.h ---------------
void loadArray();

//--- setup.cpp -------------
#include "GLOBALS.h"

extern int gArray[A][B][C];

void loadArray() {

    // set up some arbitrary test values
    gArray[1][1][1] = 99;
    gArray[1][13][1] = 13;
}

и в testaccess.h & testaccess.cpp я изменил два тестовых значения:

// --- testaccess.h -------------------------
int testArray();

// --- testaccess.cpp -----------------------
#include "GLOBALS.h"

extern int gArray[A][B][C];

void testArray() {
    gArray[1][1][1] = 9900;
    gArray[1][13][1] = 1300;
}

Наконец, в своем основном коде я провел тестирование:


#include <Arduino.h>
#include "GLOBALS.h"
#include "setup.h"
#include "testaccess.h"


extern int gArray[A][B][C];

void setup() {
  Serial.begin(9600);
  // set the test values
  loadArray();
  
  // and print them to the serial port to view
  Serial.println(gArray[1][1][1]);   //should be 99
  Serial.println(gArray[1][13][1]);  //should be 13
  Serial.println("----------");

  // now modify one of the values and print it:
  gArray[1][13][1] += 10;
  Serial.println(gArray[1][13][1]);  // should be 23
  Serial.println("----------");

  // and now modify both values in a different module
  testArray();
  Serial.println(gArray[1][1][1]);   // should be 9900
  Serial.println(gArray[1][13][1]);  // should be 1300
}

... и результат на последовательном порту был ...

99        
13        
----------
23        
----------
9900      
1300  

После двух недель борьбы я могу двигаться дальше!

Всем спасибо за помощь и вдохновение.

person Gotty    schedule 16.10.2020

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

GLOBAL.h

const int A = 30;
const int B = 20;
const int C = 10;

extern int gArray[A][B][C];

GLOBAL.cpp

#include "GLOBAL.h"
int gArray[A][B][C];

Включите GLOBAL.h везде, где вам нужен доступ к gArray.

person Anonymous1847    schedule 15.10.2020

Проблема в том, что вы пишете

int gArray[A][B][C];

значения констант A, B и C должны быть известны компилятору, поскольку компилятор должен выделить соответствующую память для gArray. Поскольку вы заявили, что константы являются внешними, это не поможет компилятору, потому что они могут измениться, когда вы ссылаетесь на другую версию объектного файла, где известны A, B и C.

В качестве одного предложения сохраните

const int A=30;
const int B=20;
const int C=10;
extern int gARRAY[A][B][C]; /* declares gARRAY but does not allocate memory for it */

и положи

#include "GLOBALS.h"
int gArray[A][B][C]; /* allocates memory for gArray */

в один из ваших файлов реализации (например, setup.cpp). В противном случае вы столкнетесь с проблемами, если GLOBALS.h включен в несколько файлов реализации. В этом случае компоновщик будет жаловаться, что gARRAY был определен несколько раз (по одному разу в каждой единице компиляции, в которую вы включили GLOBALS.h).

person Tom    schedule 15.10.2020