如何将char数组定义为常量?

问题描述 投票:4回答:2

C / C ++菜鸟在这里。我已经在头文件中定义了...

typedef unsigned char BitChar[9]; // 8 data bytes (chars) and one width byte (char)

extern BitChar BitFont[];

而且我在cpp文件中有这个...

BitChar BitFont[] = {
    B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,2, // 32 - Space
    B10000000,B10000000,B10000000,B10000000,B10000000,B00000000,B10000000,B00000000,1, // 33 - !
    ...
    B00000000,B00000000,B11100000,B11100000,B11100000,B00000000,B00000000,B00000000,3, // 127 - Unknown
};

它可以编译,并且看起来运行良好。但是,由于它永远不会改变,因此我认为应该将其标记为常量。我该如何标记呢?我所期望的,加上'const',会引发编译错误,所以我很困惑。这是错误...

error: invalid initialization of reference of type 'unsigned char (&)[9]' from expression of type 'const unsigned char [9]' 
c++ c arduino const
2个回答
9
投票

只需添加const。这个

extern const BitChar BitFont[];
...
const BitChar BitFont[] = {
    B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,2, // 32 - Space
    B10000000,B10000000,B10000000,B10000000,B10000000,B00000000,B10000000,B00000000,1, // 33 - !
    ...
    B00000000,B00000000,B11100000,B11100000,B11100000,B00000000,B00000000,B00000000,3, // 127 - Unknown
};

在C中应该可以很好地工作。(假设您的编译器知道这些B00000000标识符的含义。)

这在C ++中也可以很好地工作。 C ++版本中唯一可能出现错误的地方是基于const的C ++特定属性。如果定义没有看到声明,那么您还必须在定义中指定显式extern

extern const BitChar BitFont[] = {
    B00000000
    ...

因为在C ++ const中,对象默认具有internal链接。但是,如果声明中已经包含extern并且定义可以看到该声明,则定义中的extern是可选的。

您引用的错误消息表明,您试图在代码中的某个地方尝试使用const限定的BitChar &数组初始化类型为unsigned char (&)[9](又名BitChar)的引用。这将不起作用,因为它违反了const-correctity的基本规则。该引用也必须成为const限定符,即,它必须更改为const BitChar &(又名const unsigned char (&)[9])。


1
投票

请注意,CONST仍会占用RAM空间。对于大型常量数组,您可能需要考虑将其放入程序空间(又名Flash或非易失性空间)中。下面是一个示例。

const uint8_t BitFont[] PROGMEM = {
    B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,2, // 32 - Space
    B10000000,B10000000,B10000000,B10000000,B10000000,B00000000,B10000000,B00000000,1, // 33 - !
    B00000000,B00000000,B11100000,B11100000,B11100000,B00000000,B00000000,B00000000,3, // 127 - Unknown
};
#define BITFONT_X_SIZE (sizeof(BitFont)/sizeof(BitFont[0]))

void setup() {
  Serial.println("");
  Serial.print(F("BitFont[] = "));
  for(int y = 0 ; y < BITFONT_X_SIZE ; y++) {
    Serial.print(pgm_read_byte_near( &(BitFont[1]) ) );
    Serial.print(F(","));
  }
  Serial.println("");
}

请注意,正在发生三件事。首先,avr-gcc使用PROGMEM宏将其链接到程序空间。其次,使用pgm_read_byte_near函数从程序空间读取指针。因为它需要使用特殊的操作码来读取程序空间。

第三,与您的示例没有直接关系,但是与Serial.print()中使用的F()函数类似,该函数同样将常量字符串放入程序空间。否则,Serial.print中的字符串会消耗静态内存。


或者您可以创建矩阵

#define BRICK_COLUMNS 9
const uint8_t BitFont[][BRICK_COLUMNS] PROGMEM = {
    {B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,2}, // 32 - Space
    {B10000000,B10000000,B10000000,B10000000,B10000000,B00000000,B10000000,B00000000,1}, // 33 - !
    {B00000000,B00000000,B11100000,B11100000,B11100000,B00000000,B00000000,B00000000,3} // 127 - Unknown
};
#define BITFONT_X_SIZE (sizeof(BitFont)/sizeof(BitFont[0]))

void setup() {
  Serial.println("");

  for(int x = 0 ; x < BITFONT_X_SIZE ; x++) {
    Serial.print(F("BitFont["));
    Serial.print(x);
    Serial.print(F("][y] = "));
    for(int y = 0 ; y < BRICK_COLUMNS ; y++) {
      Serial.print(pgm_read_byte_near ( &(BitFont[1]) ));
      Serial.print(F(","));
    }
    Serial.println("");
  }
  Serial.println("");
}
© www.soinside.com 2019 - 2024. All rights reserved.