如何在C++函数体外的表达式中使用static_assert

omvjsjqw  于 2022-12-29  发布在  其他
关注(0)|答案(1)|浏览(125)

我正在用C编写一个宏PAGE_ALIGN,如下所示。

#include <stdio.h>

#define PAGE_ALIGN(x) ((x) & 0xfffff000U)

int main() {
    printf("0x%08x\n", PAGE_ALIGN(0x12345678U));
}

现在,我想确保用户向PAGE_ALIGN传递了正确的类型,我使用_Static_assert()执行Assert,并且运行良好。

#define PAGE_ALIGN(x) (({_Static_assert(sizeof(x) == 4); x;}) & 0xfffff000U)

但是,我的一些代码在函数中没有使用PAGE_ALIGN,例如,在定义全局变量时:

char a[PAGE_ALIGN(0x12345678U)];

然后我得到编译错误

a.c:3:24: error: braced-group within expression allowed only inside a function
    3 | #define PAGE_ALIGN(x) (({_Static_assert(sizeof(x) == 4); x;}) & 0xfffff000U)
      |                        ^
a.c:5:8: note: in expansion of macro 'PAGE_ALIGN'
    5 | char a[PAGE_ALIGN(0x12345678U)];
      |        ^~~~~~~~~~

有没有办法定义PAGE_ALIGN,使宏在函数之外工作?
完整a.c

#include <stdio.h>

#define PAGE_ALIGN(x) (({_Static_assert(sizeof(x) == 4); x;}) & 0xfffff000U)

char a[PAGE_ALIGN(0x12345678U)];

int main() {
    printf("0x%08x\n", PAGE_ALIGN(0x12345678U));
}

**更新:**这是提出此问题的动机。

我在写一个操作系统,处理物理地址和虚拟地址,分别是32位和64位,虚拟地址在32位是32位,在64位是64位,所以虚拟地址用unsigned long,物理地址都是64位,所以用unsigned long long,我在写一个头文件来区分这些不同的类型
例如,页面大小宏为:

#define VA_PAGE_SIZE_4K 0x1000UL  // VA for virtual address
#define PA_PAGE_SIZE_4K 0x1000ULL // PA for physical address

然后定义用于对齐的宏:

#define VA_PAGE_ALIGN_UP_4K(x) (((x) + VA_PAGE_SIZE_4K - 1) & ~(VA_PAGE_SIZE_4K - 1))
#define PA_PAGE_ALIGN_UP_4K(x) (((x) + PA_PAGE_SIZE_4K - 1) & ~(PA_PAGE_SIZE_4K - 1))

请想象一下还有其他宏,比如VA_PAGE_ALIGN_UP_2MVA_PAGE_ALIGN_UP_1G ...
我的操作系统有一个固定的物理地址大小(比如4 GiB),我需要一个身份Map页表。所以我可以使用对齐宏来计算我需要支持多少页表条目。当然,由于多级分页,还有页目录等。

// maximum physical memory, 4G
#define MAX_PHYS_MEM 0x100000000ULL

// number of page table entries
#define PAGE_TABLE_NELEMS (PA_PAGE_ALIGN_UP_4K(MAX_PHYS_MEM) / PA_PAGE_SIZE_4K)

// Define page table (global variable)
unsigned long page_table[PAGE_TABLE_NELEMS];

// number of page directory entries
#define PAGE_DIRECTORY_NELEMS (PA_PAGE_ALIGN_UP_2M(MAX_PHYS_MEM) / PA_PAGE_SIZE_2M)

// Define page directory (global variable)
unsigned long page_directory[PAGE_DIRECTORY_NELEMS];

// ...

但是,在其他代码中,我想确保PA_PAGE_ALIGN_UP_4KVA_PAGE_ALIGN_UP_4K没有混合使用。也就是说,PA_PAGE_ALIGN_UP_4K只在unsigned long long上使用,VA_PAGE_ALIGN_UP_4K只在unsigned long上使用。所以我想在这些宏中添加一个静态Assert。但是添加一个静态Assert会在上面的page_tablepage_directory中导致编译错误。

pb3skfrl

pb3skfrl1#

@Tavian巴恩斯的评论解决了我的问题,我更新的程序看起来像:

#include <stdio.h>

#define PAGE_ALIGN(x) (sizeof(struct { _Static_assert(sizeof(x) == 4); int dummy; }) * 0 + ((x) & 0xfffff000U))

char a[PAGE_ALIGN(0x12345678U)];

int main() {
    printf("0x%08x\n", PAGE_ALIGN(0x12345678U));
}

相关问题