【问题标题】:Adding structure to an array of char in C将结构添加到C中的char数组
【发布时间】:2012-08-19 06:21:20
【问题描述】:

我有一个 C 程序,它接收一个 64 字节的 char 数组(通过 USB 传递)。根据第一个字节(指示命令类型),我想在 char 数组上“强加”一个结构以使代码更清晰。

例如,如果命令代码是 10,我会期望类似:

struct
{
    uint8_t commandNumber;
    uint16_t xPos;
    uint16_t yPos;
    int32_t identificationNumber;
 } commandTen;

所以我想将我的 char packet[64] 'onto' commandTen 强制转换,然后使用以下内容访问字段:

localVar = commandTenPacket->xPos;

如何在 C 中实现这一点?

提前致谢!

【问题讨论】:

  • 您需要“打包”结构以消除对齐填充。
  • 这不能便携。你可能会更好地读取字节并直接从字节构建值。
  • 在我看来关键字 union 对处理这个问题大有帮助。
  • 您可能会发现这篇文章很有用:stackoverflow.com/q/371371/951890
  • 也许我应该补充一点,该代码适用于资源非常有限的 AVR 微控制器,因此可移植性不如节省 RAM 重要。由于我有 64 字节的缓冲区,因此我正在寻找一种以更易读的方式访问它的方法,尽可能不使用更多 RAM(这就是为什么不希望使用库或复制到局部变量的原因)。

标签: c arrays struct


【解决方案1】:

首先,正如其他人所说,您必须确保您的 struct 没有填充。你的编译器可能有一个扩展,#pragma pack 左右。

为您的每个用例定义一个struct,而不是您的示例中的变量。

然后定义一个union

typedef union overlay overlay;

union overlay {
 uint8_t raw[64];
 struct type10 command10;
 struct type42 command42;
};

现在创建一个该类型的缓冲区

overlay buffer;

将“原始”部分提供给接收数据的函数:getit(buffer.raw)。然后

switch (buffer.raw[0]) {
 case 10: {
   // use buffer.command10
   break;
 }
 case 42: {
   // use buffer.command42
 }
}

C 标准保证这可以正常工作,因为您正在以uint8_t AKA unsigned char 阅读所有内容。事实上,unions 的主要用例就是这种“类型惩罚”。整个网络层使用不同类型的 IPv4、IPv6 等地址以类似的方式工作。

【讨论】:

  • 您也可以将uint8_t和命令代码直接添加到union;这样检查可能会更优雅一些。
  • @MichałGórny,是的,但这些东西确实是品味问题。我个人更愿意总是“看到”raw[0] 以提醒某处存在字节传输。
【解决方案2】:

不要施放。使用memcpy

char packet[64];
...

assert(sizeof commandTen <= sizeof packet);
memcpy(&commandTen, packet, sizeof commandTen);

这假设大小和内存布局正确匹配(基于强制转换的解决方案将使用相同的假设)。

【讨论】:

    【解决方案3】:

    有一种使用指针的方法。让我试着这样解释:

    struct commandX {
       int x;
    };
    struct commandMessage {
       char[8] msg;
    };
    
    char* message = (char*) malloc(sizeof(char)*9); // this will allow us a struct 
                                                    // size of 8 bytes, since the
                                                    // first byte will store the
                                                    // information on how to inter-
                                                    // the memory (or you do it in
                                                    // a different way).
    // 1. determine your offset
    //    in this case, it would be the length of the command on how to interpret.
    //    basically, it has to be the count of bytes from the
    //    beginning of your message to the start of your struct
    int offset = sizeof(char) * 1;
    // 2. read the command (that would be: message[0])
    // 3. now get rid of the type information, so that you can address every byte
    void* temp = (void*) message;
    // 4.1 if it is commandX:
    struct commandX *x_temp = (struct commandX*) (temp+offset);
        // use x_temp->x
    // 4.2 if it is commandMessage:
    struct commandMessage *msg_temp = (struct commandMessage*) (temp+offset)
       // use msg_temp->msg
    

    【讨论】:

      猜你喜欢
      • 2022-01-18
      • 2021-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-07
      • 2014-12-13
      • 1970-01-01
      相关资源
      最近更新 更多