非平凡的指定初始化器

问题描述 投票:0回答:1

我目前正在开发一个操作系统并致力于 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++ operating-system
1个回答
1
投票

数组的

[/*...*/] = 
初始化语法根本不是标准 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)]
也可能有效,但形式上是不正确的。

© www.soinside.com 2019 - 2024. All rights reserved.