I am currently working on an OS and working on the utils section. Specifically, on the tmp dir. I have came up with this code,
#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,
};
Now, afaik non-trivial designated initializers are not supported in C++, so one option I thought of is compiling the file as a C file. Now, I wonder, is there a workaround? Is it actually the ideal solution?
Thanks in advance.
>Solution :
The [/*...*/] = initializer syntax for arrays isn’t standard C++ at all.
But you don’t need it in C++. You can just initialize the array in the same way that you would do it at block scope with the help of a lambda and 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) is the standard-C++ form for the alignment attribute.
constinit assures that the initialization happens at compile-time, not runtime. It makes the compiler complain if initialization at compile-time is not possible.
std::array has the benefit of having the normal function passing behavior of non-array object types, so it can be returned from the function directly.
The above requires C++20 for constinit, otherwise only C++14. But without constinit you are yourself responsible for making sure that the initialization can be done at compile-time, i.e. is a constant expression.
All of the #define constants can be constexpr auto variables in C++ instead as well. There is no good reason to #define such constants in C++11 and later (except if you need them in the preprocessor).
Also, if you don’t intent to modify tmp_pgdir, then declare it constexpr instead of constinit. This, in addition to assuring compile-time initialization, will make the variable non-modifiable as well and gets rid of the C++20 requirement for constinit.
In order to obtain a pointer to the beginning of the array use tmp_pgdir.data() or &tmp_pgdir[0] instead of just &tmp_pgdir or tmp_pgdir. &tmp_pgdir will probably also work if the target isn’t aware of the pointer type, but it is formally wrong. To get a pointer to one-past-the end use &*std::end(tmp_pgdir) or tmp_pgdir.data() + std::size(tmp_pgdir). Again, just &tmp_pgdir + 1 or std::end(tmp_pgdir) or &tmp_pgdir[std::size(tmp_pgdir)] will probably work as well, but are formally incorrect.