在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++)
{
...
}