为何ARM GCC 6.3.0未为static const字符数组创建RAM变量?
以下是测试代码:
static const char kFmt[] = "some string: - %s"; char buf[sizeof(kFmt) + 10]; snprintf(buf, sizeof(buf), kFmt, "string");
使用ARM GCC 6.3.0编译时发现:
- 当定义为
static const char kFmt[]时,编译器没有在RAM中创建额外的char数组,而是直接把指向Flash中字符串字面量的指针传给snprintf; - 若移除
const关键字改为static char kFmt[],则会在RAM中创建额外数组并传入snprintf。
想确认:这种行为是C++标准明确规定的,还是属于编译器优化,可能因编译器不同而存在差异?
带
const的场景:
C++标准明确允许,用字符串字面量初始化的static const char[]类型数组,编译器可以直接将其放在只读存储区(比如Flash),无需在RAM中复制一份。因为const限定了数组不可修改,程序运行过程中不会对它执行写入操作,完全可以直接复用只读存储区里的字面量,不需要额外占用RAM。这属于标准许可的实现方式,并非单纯的编译器优化——不过具体存储位置可能由编译器根据目标平台调整,但标准保证它处于只读空间。不带
const的场景:
去掉const后,static char[]是可修改的静态数组。C++标准要求这类数组必须占用可写内存(比如RAM),因为程序理论上随时可能修改它的值。所以编译器必须在RAM中创建数组实例,并把字符串字面量的内容拷贝进去,绝对不能直接复用只读存储区的字面量——否则程序尝试修改时会触发写只读内存的错误,这部分是标准明确规定的,所有合规编译器都会这么做。跨编译器差异说明:
对于带const的情况,虽然标准允许直接使用只读存储区的字面量,但不同编译器可能有不同的默认行为。比如部分编译器可能默认还是会在RAM中创建拷贝,直到开启特定优化选项;但所有符合标准的编译器都必须支持将static const数组放在只读存储区的行为。而不带const的情况,不存在跨编译器差异,所有合规编译器都会在可写内存中创建数组实例。
内容的提问来源于stack exchange,提问作者Konstantin T.

