需求产生的背景
在开发某通信应用时,由于某些原因,需要将接收的结构体A
转换成另外一结构体B
进行使用,其实它们是完全等价的。但在开发的过程中,由于A
和B
并不是来自于同一头文件,因此会存在潜在的结构体不一致的情况。为了避免这种潜在的错误导致的运行时错误,我们在收到结构体A
的时候比较了A
和B
的大小,至少保证其大小一致,在进行内存操作时是安全的,其代码大致如下:
void onRecvData(const struct DataA *data)
{
if (sizeof(DataA) != sizeof(DataB)
{
std::cout << "size not match..." std::endl;
return;
}
struct DataB dst;
memcpy(&dst,data,sizeof(DataA));
// do something else
}
上面的代码运行的很好,没啥问题。在某次发布软件后,测试返回好几个测试用例都失败了,于是一个个的排查,看到的日志是"size not match..."。嗯,原来是输入的结构体struct DataA
没有按照文档进行设计导致的。
上面这种情况,我们只能在发布软件之前自己运行测试程序,然后过滤日志,排查是否存在大小不匹配的情况。作为一个开发人员,当然不愿意手动执行这些操作了,那么该如何解决呢?答案就是static_assert
。
static_assert 介绍
static_assert
很简单,它和assert
的唯一区别就是前者是进行编译期的静态检查,不存在运行时开销,如果断言失败会导致编译失败;后者是运行时判断,如果断言失败会导致程序被kill
掉。static_assert
原型如下:
// 在con为false的时候,将输出exp错误信息,并且导致编译无法通过
static_assert(con,exp)
利用static_assert进行编译期错误检查
struct DataA
{
int32_t a;
char c;
int64_t d;
}
struct DataB
{
int32_t a;
int64_t d;
}
struct DataC
{
int32_t a;
int64_t d;
}
void static_assert_test()
{
// 本行将导致编译失败,因为这两个结构体大小不一致
static_assert(sizeof(struct DataA) == sizeof(struct DataB),"DataA and DataB size not match...");
// 编译OK
static_assert(sizeof(struct DataC) == sizeof(struct DataB),"DataC and DataB size not match...");
}