我将struct定义为:
typedef struct cr3_page_entry
{
uint64_t ignored : 2; // ignored
uint64_t pwt : 1; // page-level write-through; indirectly determines the memory type used to access the PML4 table during linear-address translation (see Section 4.9.2)
uint64_t pcd : 1; // page-level cache disable; indirectly determines the memory type used to access the PML4 table during linear-address translation (see Section 4.9.2)
uint64_t ignored2 : 7; // ignored
uint64_t address : 53; // rest is address up to MAXPHYADDR, then zeros
} cr3_page_entry_t;
这是一个uint64_t,如果你看一下(64位大小的结构)。现在,我有一个汇编程序函数从中返回这样的数字
extern uint64_t get_active_page();
但是,我无法直接投入其中:
cr3_page_entry_t entry = (cr3_page_entry_t) get_active_page();
因为我收到错误:
memory/paging.c:19:2: error: conversion to non-scalar type requested
cr3_page_entry_t entry = (cr3_page_entry_t) get_active_page();
这可以在不为某些指针转换创建另一个堆栈变量的情况下完成吗?
答案 0 :(得分:4)
使用union
和uint64_t
结构定义cr3_page_entry_t
。然后分配给uint64_t
成员。
typedef union _cr3_u
{
uint64_t i;
cr3_page_entry_t str;
} cr3_u;
cr3_u my_data;
my_data.i = get_active_page();
答案 1 :(得分:3)
最便携的解决方案是在结构实例和memcpy()
变量之间uint64_t
。 C99及更高版本(以及许多早于此的编译器)允许通过联合进行类型惩罚。在这两种情况下,都没有指定位域中位的确切布局,因此您应该检查它是否是您对编译器的期望。一个不太安全的解决方案是*(uint64_t*)(&struct_instance)
。请务必与static_assert()
或#ifdef
确认sizeof(struct cr3_page_entry) == sizeof(uint64_t)
。如果您关心编译器之间的可移植性,还应该检查字段的对齐方式是否符合预期。
您无法做到这一点的一个原因是未指定位域的内部布局。编译器不必打包它们,或者甚至将它们对齐为64位整数的有效地址。例如,在Sparc 64上,uint64_t
必须在8字节边界上对齐,因此如果您编写一堆小位域并且编译器将它们对齐,就好像它们是uint8_t
一样,{{1或者uint16_t
,尝试将结构加载为uint32_t
会导致程序崩溃并出现错误。
答案 2 :(得分:2)
你可以通过宣布完全避免演员阵容:
extern uint64_t get_active_page();
为:
extern cr3_page_entry_t get_active_page();
代替?
答案 3 :(得分:1)
C不允许您转换为结构类型。在99%的情况下,这是没有意义的,你的情况是一个罕见的例外。
我建议如下:
static inline struct cr3_page_entry make_cr3_page_entry(uint64_t x)
{
struct cr3_page_entry ret;
assert( sizeof ret == sizeof x );
memcpy( &ret, &x, sizeof x );
return ret;
}
注意:使用别名强制转换会违反严格的别名规则。