在c中递增联合数据
我对工会有点不熟悉,读过一些关于工会的书,我很难弄明白这一点 有人为我定义了一个联盟:在c中递增联合数据,c,struct,unions,C,Struct,Unions,我对工会有点不熟悉,读过一些关于工会的书,我很难弄明白这一点 有人为我定义了一个联盟: union CANDATA // Unionize for easier cooperation amongst types { unsigned long long ull; signed long long sll; u32 ui[2]; u16 us[4]; u8 uc[8]; u8 u8[8];
union CANDATA // Unionize for easier cooperation amongst types
{
unsigned long long ull;
signed long long sll;
u32 ui[2];
u16 us[4];
u8 uc[8];
u8 u8[8];
s32 si[2];
s16 ss[4];
s8 sc[8];
};
还有一个结构将此联合作为其成员之一:
struct CANRCVBUF // Combine CAN msg ID and data fields
{ // offset name: verbose desciption
u32 id; // 0x00 CAN_TIxR: mailbox receive register ID p 662
u32 dlc; // 0x04 CAN_TDTxR: time & length p 660
union CANDATA cd; // 0x08,0x0C CAN_TDLxR,CAN_TDLxR: Data payload (low, high)
};
我正在创建CANRCVBUF的一个实例:
static struct CANRCVBUF increasingMessage = {
0x44400000, /* 11 bit id */
0x00000002, /* 2 data bytes */
{
0x0000
}
};
接下来,我要做的是创建一个循环,增加increasingMessage的数据部分。这就是我遇到麻烦的地方。我的尝试是:
if(increasingMessage.cd + 1 > 65535) {
increasingMessage.cd = 0x0000;
} else {
increasingMessage++;
}
我意识到,通过使用increasingMessage.cd
我正在访问联合体,而不是联合体中的数据。我的问题是,在创建递增消息时,我如何知道使用了哪个联盟成员
非常感谢任何提示通常当您使用工会时,您应该知道哪个会员的数据正确。如果不可能,则需要在
CANRCVBUF
中添加一个变量,以指示哪个成员是正确的。这是一种使用继承的C方式。您需要提供您正在寻址的工会成员。编译器需要知道是否要测试ull
(作为无符号长字符)或sc[0]
(作为无符号字符)或任何其他成员
在您的情况下,您可能希望使用
if(increasingMessage.cd.us[3] + 1 > 65535) {
...
--也就是说,如果工会的这一部分是你要找的号码。(您的代码并不完全清楚这一点。)
联合成员的访问方式与结构成员相同,唯一的区别是它们的存储方式不同
请注意,我选择的特定字段永远不会>65535。。。因此,请仔细选择您的测试成员…在
联合中,所有字段都是重叠的。因此,联合的大小等于其中最大字段的大小
关于你的问题:
您需要通过在increasingMessage.cd
之后添加对该字段的引用来指定要应用该操作的字段的名称。例如,increasingMessage.cd.ull
。但请注意,每次更改此字段时,联合中的所有其他字段也将受到影响,因为它们彼此重叠
通常,为了指示相关字段,整个联合
被放置在结构
中,该结构包含一个额外的枚举
,用于指示该字段。例如:
typedef enum
{
MSG_1,
MSG_2,
MSG_3,
...
}
msg_type_e;
typedef struct
{
msg_type_e type;
union CANDATA cd; // 0x08,0x0C CAN_TDLxR,CAN_TDLxR: Data payload (low, high)
}
msg_t;
该标准说它是接收静态初始值设定项的联盟的第一个命名成员,因此在声明它时,您隐含地说increasingMessage.cd.ull=0x0000
一般来说,在这种情况下,与工会中最大的成员合作是最有力的。如果你还不知道,那么:
increasingMessage.cd.ull++;
increasingMessage.cd.ull &= 0xFFFF;
是进行16位计数最安全的方法-如果您不知道尾数,那么您就不知道cd中的哪一个。us[0]
和cd.us[3]
是CANDATA
的最低有效16位,因此您最好保证它在本地尾数中是一致的。当然,如果必须将其传送到另一个系统,那就另当别论了,但是文档应该清楚地定义那里的任何需求。因此,如果我没有弄错您的意图,您希望循环增加message.cd,从0增加到65535。正如其他人所说,联盟的成员彼此重叠,即ull、sll、ui[2],…,都指向相同的内存。换句话说,这些不同的字段位于相同的内存地址中并存储相同的值,但是您可以通过访问不同的字段以不同的类型表示相同的值
因此,一个简单的循环就可以做到这一点,比如:
for (increasingMessage.cd.ull = 0;increasingMessage.cd.ull<65536;increasingMessage.cd.ull++)
{
}
for(increasingMessage.cd.ull=0;increasingMessage.cd.ull例如:“increasingMessage.cd.ui[0]++”或“increasingMessage.cd.ull++”或任何您希望在联合内部增加的内容。因此,您知道它将是.us[3],因为0x0000是一个int?为什么索引3(我猜是0).抱歉,只是猜测--没有足够的信息继续。这取决于你应该测试工会的哪一部分(你肯定有相关文档吗?),而且,不幸的是,关于您系统的endianness。不幸的是,没有提供太多文档。它确实注意到,使用union可以简化类型的协作。保存的数据是一个64位数据字符串,将通过CAN总线发送。我只是尝试访问在声明中创建的union部分是的,但是你不知道increasingMessage
的哪个部分只包含你的数据长度。如果你确定整个成员只包含一个数字,你可以测试increasingMessage.cd.ull
——一个完整的64位值。@EricPostChill我的错了,很抱歉。我将编辑我的答案以符合要求
for (increasingMessage.cd.ull &= 0xFFFFFF00;(increasingMessage.cd.ull & (0x000000FF))<65536; increasingMessage.cd.ull++)
{
...
}