【问题标题】:trying to copy struct members to byte array in c试图将结构成员复制到c中的字节数组
【发布时间】:2010-10-03 19:37:09
【问题描述】:

我正在尝试将包含整数、字符和字符数组混合的结构的成员复制到字节数组中以发送到串行线路。到目前为止我有

struct msg_on_send
{
    char descriptor_msg[5];
    int  address;
    char space;
    char cmdmsg[5];
    char CR;
    char LF;
};

void switch_output_on()
{
    int member;
    struct msg_on_send SendMsg_on[sizeof member] =
     {

    };
    unsigned char buffer [ sizeof SendMsg_on[0] ];
    showbytes(buffer, serialize(buffer, SendMsg_on));
}

/*************************************************************************** 
*   Function:   ArrayBuild                                                 *
*   Purpose:    Uses memcopy to transfer the struct members sequentially   *
*               into an array of char                                      *
*   Arguments:                                                             *
*   Returns:    size_t i = a count of the number of bytes in the array     *
***************************************************************************/    

size_t ArrayBuild(unsigned char *dst, const struct msg_on_send *object)
{
    size_t i = 0;

    memcpy(&dst[i], &object->descriptor_msg, sizeof object->descriptor_msg);
    i += sizeof object->descriptor_msg;

    memcpy(&dst[i], &object->address, sizeof object->address);
    i += sizeof object->address;

    memcpy(&dst[i], &object->space, sizeof object->space);
    i += sizeof object->space;

    memcpy(&dst[i], &object->cmdmsg, sizeof object->cmdmsg);
    i += sizeof object->cmdmsg;

    memcpy(&dst[i], &object->CR, sizeof object->CR);
    i += sizeof object->CR;

    memcpy(&dst[i], &object->LF, sizeof object->LF);
    i += sizeof object->LF;

    return i;
}

/*********************************************************************** 
*   Function:   USARTWrite                                             *
*   Purpose:    Writes the array data to the USART data register       *
*   Arguments:  void *object = struct member                           *
*               size_t size =  size of array remaining                 *
*   Returns:    None                                                   *
***********************************************************************/

void USARTWrite(const void *object, size_t size)        
{
    const unsigned char *byte;
    for ( byte = object; size--; ++byte )
    {
        printf("%02X", *byte);
    }
    putchar('\n');
}

当我获得此代码时,我并不完全理解它是如何工作的。我可以看到 memcpy 获取结构的每个元素并将其转换为由“i”变量索引的串行流,但我不知道 USARTWrite 函数如何将其打包成字符串,或者如何加载数组我的结构初始化。

抱歉,这篇文章有点长,但我刚刚开始这个编程云雀,并试图理解这个概念。

谢谢 戴夫

编辑:

哇,很快就有很多很好的答案 - 谢谢大家。

slaz:这对我来说似乎是合乎逻辑的,我还没有真正考虑过这种方法,因为我还没有真正理解指针,但我开始看到它们是 C 的重要组成部分,所以我适当的会看看。

  • 这行代码将数据发送到我的 UART,我将用什么替换包含消息内容的数组?似乎我在这里错过了一个合乎逻辑的步骤,我有一个变量告诉我我的结构从哪里开始以及它有多大,但没有要发送的数组

    USART_SendData(USART1, message_on_contents[array_count]);
    

哈珀·谢尔比:谢谢你的描述,它让我更清楚了。

rgds

戴夫

【问题讨论】:

  • 你要找的工作是“序列化”。重新标记。
  • 不是很挑剔,但在大西洋的这一边,我们使用“s”而不是“z”。真的只是英语的语义,很公平。戴夫

标签: c arrays serialization struct memcpy


【解决方案1】:

您的struct 只是字节数组,它不包含指向它的指针。

成员到成员的复制很可能是为了应对对齐问题,因为(char*) &address 可能大于((char*) &descriptor_msg) + 5

USARTWrite 将结构字节的HEX 代码发送到stdout,但会丢弃对齐。用不同的对齐策略编译这段代码会导致不同的输出。

将您的结构声明包含在#pragma pack(push, n)#pragma pack(pop) 中以强制对齐,然后逐字节复制您的结构。

【讨论】:

  • 问题没有指定平台或编译器,标签也没有。根据定义,编译指示不是标准的,并且因编译器而异。建议 pragma 时,请至少由编译器限定。
【解决方案2】:

这很简单: 1. ArrayBuild 接受一个指向 msg_on_send 结构的指针,并且对于其中的每个成员,使用 memcpy 将字节复制到传入的 char 数组中 -

char byteArray[17]; // This assumes 4-byte ints
                    // be careful though, the length *must* be long enough, or 
                    // Bad Things will happen
size_t msgSize; // Holds the size of the message built by ArrayBuild,
                // passed to USARTWrite
struct msg_on_send myMessage;
// Code to fill up myMessage appropriately

msgSize = ArrayBuild(byteArray, &myMessage); // need the & to pass a pointer as required

USARTWrite(myMessage, msgSize);

USARTWrite 只给出了一个 char 数组和一个大小 - 它依次抓取每个 char 并使用 printf() 将其作为十六进制值打印到屏幕上。

“魔法”在 ArrayBuild 中 - memcpy 将字节从源到目标的字面复制,没有翻译。假设 4 字节整数,该函数构建的数组将如下所示:

                     1 1 1 1 1 1 1 
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
|   A     |   B   |C|    D    |E|F|

A = descriptor_msg (char[5])
B = address (int)
C = space (char)
D = cmdmsg (char[5])
E = CR (char)
F = LF (char)

我假设在“真实”应用程序中,printf() 调用将被对串行端口写入的调用所取代。

【讨论】:

    【解决方案3】:

    您不必实际将结构复制到字节数组中。 您可以选择这样做:

    struct msg_on_send myMessage;
    
    // code to set myMessage to whatever values...
    
    // get a byte pointer that points to the beginning of the struct    
    uint8_t *bytePtr = (uint8_t*)&myMessage;
    
    // pass that into the write function, and it will write the amount of bytes passed in
    USARTWrite(bytePtr, sizeof(myMessage));
    

    指针的力量! :)

    【讨论】:

    • 这很常见,我看到它一直用于将大窗口 api 结构归零。不过,我不会制作临时变量 bytePtr。
    • 为什么不做这个临时变量?
    • 必须attribute ((packed)) 以保证它总是按预期工作!
    • 对不起,我不太明白你的意思,你能用更简单的方式解释一下吗——我刚开始编程。
    • 如果您使用这种技术,请确保接收端与发送设备具有相同的字节序。否则,你会得到奇怪的整数值。
    【解决方案4】:

    对不起,我直到现在才看到你的评论。 下面的代码在 Linux 上编译得很好,所以我希望它对你有用。
    printf() 以十六进制打印,每个字节将得到 2 个字符。

    #include <stdio.h>
    
    struct msg_on_send
    {
    char descriptor_msg[5];
    int  address;
    char space;
    char cmdmsg[5];
    char CR; 
    char LF; 
    };
    
    void USARTWrite(const void *object, size_t size)    
    {
        const unsigned char *byte;
          for ( byte = object; size--; ++byte )                                     
          {   
              printf("%02X", *byte);
          }   
          putchar('\n');
    }
    
    int main (int argc, char**argv)
    {
        struct msg_on_send myMsg;
        unsigned char* ptr= (unsigned char*)&myMsg;
    
        USARTWrite(ptr, sizeof(myMsg));
    
        return 0;
    }
    

    我希望这会有所帮助。

    ~
    ~

    【讨论】:

    • 因为 USARTWrite 需要一个 const void *,所以 main 中应该需要 ptr 变量。你可以这样做:USARTWrite(&myMsg, sizeof(myMsg));
    【解决方案5】:

    如果我想将结构视为字节数组,我通常使用联合将结构与字节数组组合在一起。例如:

    typedef union
    {
        struct
        { 
            char descriptor_msg[5]; 
            int  address; 
            char space; 
            char cmdmsg[5]; 
            char CR; 
            char LF; 
        };
        BYTE bytes[];
    } msg_on_send;
    

    【讨论】:

      【解决方案6】:

      完整的示例。完美的作品。在 X-CODE 9 Objective-C 下测试

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      
      struct Person
      {
          char name[20];
          int age;
      };
      
      int main()
      {
          //structure variable declaratio with initialisation
          struct Person person={"Deniss Ritchie", 60};
          //declare character buffer (byte array)
          unsigned char *buffer=(char*)malloc(sizeof(person));
          int i;
      
          //copying....
          memcpy(buffer,(const unsigned char*)&person,sizeof(person));
      
          //printing..
          printf("Copied byte array is:\n");
          for(i=0;i<sizeof(person);i++)
              printf("%02X ",buffer[i]);
          printf("\n");
      
          //freeing memory..
          free(buffer);
          return 0;
      }
      

      输出:

      Copied byte array is:
      44 65 6E 69 73 73 20 52 69 74 63 68 69 65 00 00 00 00 00 00 3C 00 00 00
      

      【讨论】:

        【解决方案7】:

        一个很好的解决方案:

        typedef union
        {
          unsigned char byte_array[14];
          struct
          {
            uint8_t descriptor_msg[5];
            uint8_t address;
            uint8_t space;
            uint8_t cmdmsg[5];
            uint8_t CR;
            uint8_t LF;
          };
        } msg_to_send_t;
        
        #define ARRAY_OF_5_BYTE {0x00, 0x01, 0x02, 0x03, 0x04}
        
        #define MSG_TO_SEND_DEFAULT \
        { \
           .descriptor_msg = ARRAY_OF_5_BYTE, \
           .address = 0x01, \
           .space = 0x02, \
           .cmdmsg = ARRAY_OF_5_BYTE,\
           .CR = 0x03, \
           .LF = 0x04, \
        } 
        
        msg_to_send_t msg = MSG_TO_SEND_DEFAULT;
        
        for(i=0; i<sizeof(msg.byte_array); i++)
            printf("%02x", msg.byte_array[i]);
        printf("\r\n");
        

        【讨论】:

        • 您能提供更多解释吗?您的代码在其他答案中没有什么不同?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-06-30
        • 1970-01-01
        • 1970-01-01
        • 2011-10-25
        • 2016-12-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多