我目前正在开发一个操作系统并致力于 utils 部分。具体来说,在 tmp 目录上。我想出了这段代码,
#include <stdint.h>
#define HIGH_KERNEL 0xc0000000
#define PAGE_SIZE 4096
#define PAGE_PRESENT (1 << 0)
#define PAGE_WRITE (1 << 1)
#define PAGE_HUGE (1 << 7)
__attribute__((__aligned__(PAGE_SIZE)))
uint32_t tmp_pgdir[1024] = {
[0] = 0x0 | PAGE_PRESENT | PAGE_WRITE | PAGE_HUGE,
[HIGH_KERNEL >> 22] = 0x0 | PAGE_PRESENT | PAGE_WRITE | PAGE_HUGE,
};
现在,C++ 中不支持非平凡的指定初始值设定项,因此我想到的一个选项是将文件编译为
C
文件。现在我想知道有没有解决方法?这真的是理想的解决方案吗?
提前致谢。
数组的
[/*...*/] =
初始化语法根本不是标准 C++。
但在 C++ 中你不需要它。您可以在 lambda 和
std::array
: 的帮助下以与在块作用域中执行初始化相同的方式初始化数组
alignas(PAGE_SIZE) constinit auto tmp_pgdir = []{
std::array<std::uint32_t, 1024> ret{}; // {} initializes to zero
ret[0] = 0x0 | PAGE_PRESENT | PAGE_WRITE | PAGE_HUGE;
ret[HIGH_KERNEL >> 22] = 0x0 | PAGE_PRESENT | PAGE_WRITE | PAGE_HUGE;
return ret;
}();
alignas(PAGE_SIZE)
是对齐属性的标准 C++ 形式。
constinit
确保初始化发生在编译时,而不是运行时。如果编译时初始化不可能,它会让编译器抱怨。
std::array
的好处是具有非数组对象类型的正常函数传递行为,因此可以直接从函数返回。
以上要求
constinit
需要C++20,否则只需C++14。但如果没有 constinit
,您自己有责任确保初始化可以在编译时完成,即是一个常量表达式。
所有
#define
常量也可以是 C++ 中的 constexpr auto
变量。在 C++11 及更高版本中没有充分的理由#define
此类常量(除非您在预处理器中需要它们)。
此外,如果您不想修改
tmp_pgdir
,请声明它 constexpr
而不是 constinit
。除了确保编译时初始化之外,这还将使变量不可修改,并消除 C++20 对 constinit
的要求。
为了获取指向数组开头的指针,请使用
tmp_pgdir.data()
或 &tmp_pgdir[0]
而不是仅使用 &tmp_pgdir
或 tmp_pgdir
。如果目标不知道指针类型,&tmp_pgdir
也可能起作用,但它在形式上是错误的。要获得指向最后一位的指针,请使用 &*std::end(tmp_pgdir)
或 tmp_pgdir.data() + std::size(tmp_pgdir)
。同样,仅使用 &tmp_pgdir + 1
或 std::end(tmp_pgdir)
或 &tmp_pgdir[std::size(tmp_pgdir)]
也可能有效,但形式上是不正确的。