2012-06-01 27 views
5

我有一个结构位字段(总共32位宽),我有一个32位变量。当我尝试变量值分配给我的结构,我得到了一个错误:如何使用位域为结构赋值?

error: conversion from ‘uint32_t {aka unsigned int}’ to non-scalar type ‘main()::CPUID’ requested.

struct CPUIDregs 
    { 
     uint32_t EAXBuf; 
    }; 
CPUIDregs CPUIDregsoutput; 


int main() { 

struct CPUID   
    { 
      uint32_t Stepping   : 4;   
      uint32_t Model   : 4;   
      uint32_t FamilyID   : 4;   
      uint32_t Type    : 2;   
      uint32_t Reserved1  : 2;   
      uint32_t ExtendedModel : 4;   
      uint32_t ExtendedFamilyID : 8;   
      uint32_t Reserved2  : 4;   
    }; 

    CPUID CPUIDoutput = CPUIDregsoutput.EAXBuf; 

你有任何想法如何做到这一点的最简单的办法?谢谢

P.S.当然,我在实际代码中有更适当的EAX价值,但我想这不影响。

+3

您可能想在这里使用'union'而不是'struct'。否则,你只能单独设置结构中的每个变量。你不能'CPUID CPUIDoutput = EAX;'你必须做'CPUIDoutput.stepping = EAX;' – andre

回答

7

不应该依赖编译器如何在内存中布局结构。有一些方法可以完成你想要的任务,但我不会推荐也不会告诉你。

做一个任务将是以下的最佳方式:

static inline void to_id(struct CPUid *id, uint32_t value) 
{ 
    id->Stepping   = value & 0xf; 
    id->Model   = (value & (0xf << 4)) >> 4; 
    id->FamilyID   = (value & (0xf << 8)) >> 8; 
    id->Type    = (value & (0x3 << 12)) >> 12; 
    id->Reserved1  = (value & (0x3 << 14)) >> 14; 
    id->ExtendedModel = (value & (0xf << 16)) >> 16; 
    id->ExtendedFamilyID = (value & (0xff << 20)) >> 20; 
    id->Reserved2  = (value & (0xf << 28)) >> 28; 
} 

并且对方

static inline uint32_t from_id(struct CPUid *id) 
{ 
    return id->Stepping 
     + ((uint32_t)id->Model << 4) 
     + ((uint32_t)id->FamilyID << 8) 
     + ((uint32_t)id->Type << 12) 
     + ((uint32_t)id->Reserved1 << 14) 
     + ((uint32_t)id->ExtendedModel << 16) 
     + ((uint32_t)id->ExtendedFamilyID << 20) 
     + ((uint32_t)id->Reserved2 << 28); 
} 
+0

现在,我只能看到这种分配方式。 – Irina

+0

@ user1430759。这是执行此操作的唯一安全/便携式方法。不要担心性能,因为这几乎都可以通过编译器进行优化。另外,请在复制粘贴代码前仔细检查数字。 – Shahbaz

+0

如果你喜欢这个答案,随时投票并接受;) – Shahbaz

1

这些是结构体成员,因此您需要直接进行赋值,或者确保赋值的RHS是类型为CPUID的值。不知道为什么你期望能够从一个整数分配给结构。

结构包含位域,并且位的总和恰好与您要分配的整数中的位数相同的事实意味着什么。为了分配目的,它们仍然不是兼容的类型。

如果这太含糊,请考虑展示更多/更好的代码。

+0

我猜在编辑的代码版本中,更明显的原因是我试图一次性将EAX分配给整个结构。所以,无论如何,如果我理解你是对的,我不能这样做?我只能分别分配每个字段? – Irina

2

只是如果somebody's兴趣,从来就得到了一个更好的解决方案为我自己问题:

*(reinterpret_cast<uint32_t *> (&CPUIDoutput)) = CPUIDregsoutput.EAXBuf; 
+1

这比我的联盟建议还要糟糕。 –

+1

@Anna,我希望你不要在实际的代码中使用这个实际的代码。问题在于编译器可以自由地在结构的成员之间添加填充以实现优化目的。所以,你不能依靠你的结构和你的号码来拥有相同的布局。即使没有填充,你的声明在大型机器中绝对是错误的。 – Shahbaz

3

使用联合。

union foo { 
    struct { 
     uint8_t a : 4; 
     uint8_t b : 4; 
     uint8_t c : 4; 
     uint8_t d : 4; 
     uint16_t e; 
    }; 
    uint32_t allfields; 
}; 

int main(void) { 
    union foo a; 

    a.allfields = 0; 
    a.b = 3; 

    return 0; 
}