为什么不能直接在C中将数字转换为struct?

时间:2015-12-03 08:11:24

标签: c struct

我将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();

这可以在不为某些指针转换创建另一个堆栈变量的情况下完成吗?

4 个答案:

答案 0 :(得分:4)

使用unionuint64_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;
}

注意:使用别名强制转换会违反严格的别名规则。