使用全局多维数组

Using global multidimensional arrays

我目前正在从事一个基于 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];
}

不要在头文件中声明 non-const 没有 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];

在您需要访问 gArray 的任何地方包括 GLOBAL.h。

问题出在你写的时候

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

编译器需要知道常量ABC的值,因为编译器需要为gArray分配相应的内存。由于您声明常量是外部常量,因此它对编译器没有帮助,因为当您 link 到目标文件的不同版本时它们可能会更改,其中 ABC 众所周知。

作为一个建议,保留

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 被多个实现文件包含,您将 运行 陷入困境。在那种情况下,linker 会抱怨 gARRAY 已定义多次(在包含 GLOBALS.h 的每个编译单元中定义一次)。

已解决!!!

首先,我认错了 - 在遵循使用 gArray[30][20][10] 的建议时,我没有注意到我已经超出了 RAM 容量!!所以,当我可能有什么应该是一个工作方法时,处理器崩溃了[没有编译器警告]。现实是我其实只需要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  

经过两周的挣扎,我现在可以继续前进了!

感谢大家的帮助和启发。