用标准(便携式)C方法代替紧凑型结构的"__attribute__ ((packed))"



将多个值转换为用于无线电传输的字节字符串必须避免不需要的字节。在ARM目标(32位(上使用GCC属性((压缩((";。这个指令是基于GCC的(正如我在这里读到的(,所以通常不可移植——这是我更喜欢的。示例:

typedef struct __attribute__ ((packed)) {
uint8_t     u8;  // (*)
int16_t     i16; // (*)
float       v;
...
uint16_t    cs;  // (*)
}valset_t;           // valset_t is more often used 
valset_t   vs;

(*(值将使用不带((packed((属性的4个字节,而不是根据需要使用一个或两个字节。按字节访问以传输:

union{
valset_t    vs;                     // value-set
uint8_t     b[sizeof(valset_t)];    // byte array
}vs_u;

使用vs_u.b[i].

  • 这里的处理时间并不关键,因为传输速度要慢得多
  • 这里也不考虑Endian,但在某些情况下可能会应用不同的C编译器
  • 这个任务的老帖子提供了一些见解,但也许C中的包装和对齐功能同时得到了改进?c(

在C中是否有更可移植的解决方案来执行此任务?

包装/填充没有标准化,因此严格来说结构/联合是不可移植的。#pragma pack(1)在某种程度上更为常见,并受到许多不同编译器(包括gcc(的支持,但它仍然不是完全可移植的。

此外,请注意,填充的存在是有原因的,这些具有非标准填充的结构在某些系统上可能是危险的或不必要的低效。

用于存储协议等的唯一100%可移植数据类型是unsigned char的阵列。如果为结构编写序列化程序/反序列化程序例程,则只能获得完全可移植的结构。这自然是以牺牲额外的代码为代价的。反序列化示例:

valset_t data_to_valset (const unsigned char* data)
{
valset_t result;
result.something = ... ;
...
return result;
}

对于特定的网络端序,您可以在同一例程内从网络端序转换为CPU端序。

请注意,您可以像上面的函数示例一样键入它。您不能编写以下代码:

unsigned char data[n] = ... ;
valset_t* vs = (valset_t*)data; // BAD

这在很多方面都是不好的:对齐、填充、严格混叠、尾数等等

不过,也可以反过来,使用unsigned char*逐字节检查或序列化结构。然而,这样做并不能解决填充字节或字节尾的问题。

最新更新