пытаясь скопировать членов структуры в байтовый массив в C - PullRequest
8 голосов
/ 27 января 2009

Я пытаюсь скопировать элементы структуры, содержащей смесь целых чисел, символов и массивов символов, в байтовый массив для отправки в последовательную строку. Пока у меня есть

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 упаковывает это в строку или как загрузить массив с помощью моя структура инициализации.

Извините, этот пост немного длинный, но я только начинаю программировать и пытаюсь разобраться с этой концепцией.

Спасибо Dave

EDIT:

Ух, много хороших ответов быстро - спасибо, ребята.

slaz: Мне кажется, это логично, я даже не задумывался об этом подходе, так как еще не разбирался в указателях, но начинаю понимать, что они являются неотъемлемой частью C, поэтому я должным образом посмотрим.

  • Эта строка кода отправляет данные в мой UART. Чем бы я заменил массив, содержащий содержимое сообщения? Похоже, я пропускаю логический шаг здесь, где у меня есть переменная, сообщающая мне, где начинается моя структура и насколько она велика, но нет массива для отправки

    USART_SendData(USART1, message_on_contents[array_count]);
    

Харпер Шелби: Спасибо за это описание, оно намного яснее.

1025 * Rgds *

Dave

Ответы [ 6 ]

7 голосов
/ 27 января 2009

На самом деле вам не нужно копировать структуру в массив байтов. При желании вы можете сделать это:

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));

Сила указателей! :)

6 голосов
/ 29 января 2009

Извините, я не видел ваш комментарий до сих пор. Приведенный ниже код компилируется в 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;
}

Надеюсь, это поможет.

~
~

1 голос
/ 08 февраля 2010

Если я хочу рассматривать структуру как массив байтов, я обычно использую объединение, чтобы объединить структуру с байтовым массивом. Например:

typedef union
{
    struct
    { 
        char descriptor_msg[5]; 
        int  address; 
        char space; 
        char cmdmsg[5]; 
        char CR; 
        char LF; 
    };
    BYTE bytes[];
} msg_on_send;
0 голосов
/ 27 марта 2018

Полный полный пример. Отлично работает. Проверено в соответствии с 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
0 голосов
/ 27 января 2009

Это довольно просто: 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 только что дан массив символов и размер - он захватывает каждый символ по очереди и выводит его на экран в виде шестнадцатеричного значения с помощью 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 () будет заменен вызовом записи в последовательный порт.

0 голосов
/ 27 января 2009

Ваш struct здесь просто массив байтов, он не содержит указателей, которые указывают на него.

Копия между членами, скорее всего, выполняется для выравнивания, так как (char*) &address, вероятно, будет больше, чем ((char*) &descriptor_msg) + 5.

USARTWrite отправляет HEX кодов байтов вашей структуры на stdout, но отбрасывает выравнивание. Компиляция этого кода с разными стратегиями выравнивания приведет к разным результатам.

Вложите объявление структуры в #pragma pack(push, n) и #pragma pack(pop) для принудительного выравнивания и просто скопируйте байты в структуру.

...