C 强制两个结构在编译时具有相同的大小?
我定义了两个数据结构,它们必须彼此保持相同的大小,应用程序才能正常运行。该结构用于PC和DSP之间的通信。DSP代码在C中,PC端为C++。 例如:C 强制两个结构在编译时具有相同的大小?,c,embedded,C,Embedded,我定义了两个数据结构,它们必须彼此保持相同的大小,应用程序才能正常运行。该结构用于PC和DSP之间的通信。DSP代码在C中,PC端为C++。 例如: struct inbound_data{ int header[5]; float val1; float val2; int trailer[3]; }; struct outbound_data{ int header[5]; int reply1; int reply2; fl
struct inbound_data{
int header[5];
float val1;
float val2;
int trailer[3];
};
struct outbound_data{
int header[5];
int reply1;
int reply2;
float dat1;
float dat2;
int filler[1];
}
稍后我会做一些类似的事情:
int tx_block[sizeof(outbound_data)];
int rx_block[sizeof(inbound_data)];
这些阵列将被传送到通信外围设备,以便在设备之间进行传输和接收
由于硬件的工作方式,两个结构的大小必须匹配,以便缓冲区大小相等。这很容易通过适当的小心来保证,但在设计周期中,数据结构偶尔会被修改。如果一个人不非常小心,并且意识到结构保持相同大小的要求(也反映在PC端代码中),混乱就会接踵而至
我想找到一种编译时方法,如果其中一个结构被修改,使其与另一个结构的大小不匹配,则不生成代码
在“标准”C中,是否有可能在编译时检查大小,如果大小不同则会失败?(我认为我的编译器至少是C99,可能不是11)。C11标准添加了一个新的关键字
\u Static\u assert
。您可以使用它在编译时测试谓词,如果它是false
,则会产生错误:
_Static_assert(sizeof(outbound_data) == sizeof(inbound_data), "sizes must match");
对于C99,您可以使用以下内容
#define C_ASSERT(x, y) { int dummy[(x) == (y) ? 1 : -1]; (void*)dummy; }
struct foo {
int f;
};
struct bar {
int b1;
//int b2;
};
int main()
{
C_ASSERT(sizeof(struct foo), sizeof(struct bar));
}
您可以添加填充以使大小相等
struct inbound_data;
struct outbound_data;
struct _inbound_data{
int header[5];
float val1;
float val2;
int trailer[3];
};
struct _outbound_data{
int header[5];
int reply1;
int reply2;
float dat1;
float dat2;
int filler[1];
};
struct inbound_data{
int header[5];
float val1;
float val2;
int trailer[3];
char padding[sizeof(struct _inbound_data) < sizeof(struct _outbound_data) ? sizeof(struct _outbound_data) - sizeof(struct _inbound_data) : 0];
};
struct outbound_data{
int header[5];
int reply1;
int reply2;
float dat1;
float dat2;
int filler[1];
char padding[sizeof(struct _outbound_data) < sizeof(struct _inbound_data) ? sizeof(struct _inbound_data) - sizeof(struct _outbound_data) : 0];
};
struct-inbound\u数据;
数据结构;
结构\u入站\u数据{
int头[5];
浮动val1;
浮动val2;
int拖车[3];
};
结构\u出站\u数据{
int头[5];
答复1;
国际答复2;
浮动dat1;
浮动dat2;
int填充[1];
};
结构入站数据{
int头[5];
浮动val1;
浮动val2;
int拖车[3];
字符填充[sizeof(结构入站数据)
当然,我可以用更短的方式编写它,而不需要重复结构成员,但我这样做是有意为了展示这个想法
struct inbound_data1 __attribute__((packed){
struct _inbound_data id;
char padding[sizeof(struct _inbound_data) < sizeof(struct _outbound_data) ? sizeof(struct _outbound_data) - sizeof(struct _inbound_data) : 0];
};
struct outbound_data1 __attribute__((packed){
struct _outbound_data od;
char padding[sizeof(struct _outbound_data) < sizeof(struct _inbound_data) ? sizeof(struct _inbound_data) - sizeof(struct _outbound_data) : 0];
};
struct-inbound\u-data1\u-attribute\u((打包){
结构\u入站\u数据id;
字符填充[sizeof(结构入站数据)
如果必须使用C99,那么我也建议使用宏。制作一个可以出现在任何地方且不会引入任何对象供优化器删除的宏的方法是将无效数组放入typedef
中。因此,更通用的静态断言如下所示:
#define CONCAT_(A,B) A##B
#define CONCAT(A,B) CONCAT_(A,B)
#define MY_STATIC_ASSERT(p, msg) typedef char CONCAT(dummy__,__LINE__) [(p) ? 1 : -1]
它被设计成模仿\u Static\u assert
。传递消息的目的是希望编译器诊断显示它。它的使用示例如下
产生:
main.cpp:4:54:错误:数组“dummy\u 13”的大小为负数
#定义MY_STATIC_ASSERT(p,msg)typedef char CONCAT(dummy_uuuuu,uuuuuuuu LINE_uuuu)[(p)?1:-1]
^~~~~~~
main.cpp:2:22:注:在宏“CONCAT_200;”的定义中
#定义CONCAT#(A,B)A##B
^
main.cpp:4:47:注:在宏“CONCAT”的展开中
#定义MY_STATIC_ASSERT(p,msg)typedef char CONCAT(dummy_uuuuu,uuuuuuuu LINE_uuuu)[(p)?1:-1]
^~~~~~
main.cpp:13:1:注意:在宏“MY_STATIC_ASSERT”的扩展中
我的静态断言(sizeof(structfoo)==sizeof(structbaz),“不匹配!”);
一直到这里,您都可以看到带有消息的静态断言
事后考虑,您可以将
dummy\uuuuuu
更改为please\u-check\u-line\uuu
将生成更具描述性的please\u-check\u-line\u 13
强制两个结构在编译时具有相同的大小
在C语言中没有标准的方法来实现这一点。只有一些方法可以防止它的发生,比如静态断言
——这可以防止错误代码的编译,但不能解决实际问题
在您的情况下,有几个问题:
- 您的结构使用的是C的朴素默认类型。这些类型不可移植,可以有任何大小。通过将
替换为int
等可以轻松修复int32\u t
- 不管整数类型如何,Endianess可能会使代码不可移植。这是一个单独的问题,我在这里不讨论,但需要考虑它,特别是对于外来的DSP
- 任何结构都可以在任何地方包含填充字节,以满足特定于系统的对齐要求。问题的根源在于对齐在不同系统上的工作方式不同。这是一个很难解决的问题
static\u assert
和一些非标准解决方案来确保结构具有预期的大小。例如#pragma pack(1)
或gccu attribute_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
等。这些都不是标准的,也不是可移植的。此外,跳过填充在许多系统上可能会有问题,并且您可能会遇到访问不对齐的问题-填充是有原因的。因此,这可能会产生比解决问题更多的问题
所以不幸的是,我们最终意识到,struct
不适合于可移植代码,特别是对于数据协议规范之类的东西
如果您需要真正的可移植、坚固的代码,那么您只有一个选择,nam