c - 用标准(便携式)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
这在多种不同的方面都是不好的:对齐、填充、严格的别名、字节序等等。
不过也可以反过来,使用 aunsigned char*
逐字节检查或序列化结构。但是,这样做仍然不能解决填充字节或字节序的问题。
推荐阅读
- python - pandas.Series.str.replace() 基于另一个系列
- oop - D中类的比较运算符重载?
- android - 如何在 Room @Query 中使用参数字段?
- ios - RxSwift:结合两个网络请求返回一个值
- powerbi - Power BI:季度环比百分比变化
- google-apps-script - 日期过后删除 Google 表格中的一行
- firebase - 使用 POST 将单个文件自动导入到 Firestore:https://firestore.googleapis.com/v1beta1/{database}/documents.commit?
- php - 如何为 php/html 中的每个评论设置单独的背景颜色?
- git - 如何告诉 PyCharm 不要将 node_modules 发送到 git repo?
- python - 在 Windows 中使用 python3 时,如果不按回车就不可能从屏幕上输入单个字符,这仍然是真的吗?