使用 static_assert 验证结构和 uint32_t 的 typedef 联合中的位域

Using static_assert to verify bitfields in a typedef union of a struct and an uint32_t

我正在尝试将 static_assert 用于 FPGA 的寄存器,并定义了以下结构与位域和所有变量的联合。但是每当我尝试编译时,static_assert 都不会编译,而且我会收到一条错误消息,指出变量没有命名类型。如果我尝试转发声明,它并不能解决问题。我不确定让 static_assert 工作的正确模式是什么。对编写以下代码的正确方法有什么想法吗?

so.h:

#include <stdint.h>

#define t_f2bits_addr (0x0000)

typedef union {
    struct {
        uint32_t do_it : 1;
        uint32_t fault : 1;
    } field;
    uint32_t all;
} t_f2bits_type;
#define t_f2bits_ptr (*(volatile t_f2bits_type *)t_f2bits_addr)

t_f2bits_type myVar; 
myVar.field.do_it = 0x1;
myVar.field.fault = 0x1;
static_assert(myVar.all == 0x3, "Not equal");

so.c

#include "so.h"

int main() 
{
    return 0;
}

运行:

g++ so.c
In file included from so.c:1:0:
so.h:15:1: error: ‘myVar’ does not name a type
 myVar.field.do_it = 0x1;
 ^~~~~
so.h:16:1: error: ‘myVar’ does not name a type
 myVar.field.fault = 0x1;
 ^~~~~
so.h:17:1: error: non-constant condition for static assertion
 static_assert(myVar.all == 0x3, "Not equal");
 ^~~~~~~~~~~~~
so.h:17:1: error: the value of ‘myVar’ is not usable in a constant expression
so.h:14:15: note: ‘myVar’ was not declared ‘constexpr’
 t_f2bits_type myVar;
               ^~~~~

Any ideas of the correct way to write the following code?

没有正确的方法。无法使用 static_assert 检查位域是否在特定位置。

您正在使用 C++。不要使用工会。编写一个带有访问器的普通 class,访问器使用掩码访问特定位 - 这种方式清晰、可移植且保证工作。或者使用 std::bitset.

在 C++20 中,您可以使用 std::bit_cast:

struct field {
    uint32_t do_it : 1;
    uint32_t fault : 1;
};
constexpr field myVar = [](){
    field myVar;
    myVar.do_it = 0x1;
    myVar.fault = 0x1;
    return myVar;
}();
static_assert(std::bit_cast<uint32_t>(myVar) == 0x3, "Not equal");

Demo(只有 msvc 有 std::bit_cast)。

请注意,位域确实是特定于实现的(考虑字节顺序),并且 static_assert 可能通过或不通过取决于 compilers/architecture/...

不要使用位域,使用老式的位掩码

namespace FpgaRegister
{
    constexpr uint32_t do_it = 1 << 0;
    constexpr uint32_t fault = 1 << 1;

    constexpr uint32_t all = do_it | fault;
}

static_assert(FpgaRegister::all == 0x3, "Not equal");