Reputation: 377
I am attempting to copy the members of a struct containing a mixture of ints, char's and arrays of chars into a byte array to send to a serial line. So far I have
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');
}
As I obtained this code, I don't fully understand how it works. I can see that the memcpy takes each element of the struct and makes it into a serial stream indexed by the 'i' variable, but I don't know how the USARTWrite function packetises this into a string, or how to load the array with my struct initialisation.
Sorry this post is a bit long, but I'm just starting this programming lark, and trying to get my head around this concept.
Thanks Dave
EDIT:
wow, many good answers quickly - thanks guys.
slaz: That seems logical to me, I hadn't really thought about that approach as I haven't really got my head around pointers yet, but I am beginning to see that they are an essential part of C, so I duly will have a look.
This line of code sends the data to my UART, what would I replace the array containing the message contents with? It seems like I am missing a logical step here where I have a variable telling me where my structure starts and how big it is, but no array to send
USART_SendData(USART1, message_on_contents[array_count]);
Harper Shelby: Thank you for that description, it makes it much clearer in my mind.
rgds
Dave
Upvotes: 10
Views: 41468
Reputation: 81
A good solution:
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");
Upvotes: 1
Reputation: 1239
Full complete example. Perfectly works. Tested under 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;
}
Output:
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
Upvotes: 2
Reputation: 776
If I want to treat a structure as an array of bytes I typically use a union to combined the structure with a byte array. For example:
typedef union
{
struct
{
char descriptor_msg[5];
int address;
char space;
char cmdmsg[5];
char CR;
char LF;
};
BYTE bytes[];
} msg_on_send;
Upvotes: 1
Reputation: 2210
Sorry, I didn't see your comment until just now.
The code below compiles on Linux just fine, so I hope it works for you.
printf() is printing in hex, you will get 2 characters for each byte.
#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;
}
I hope this helps.
~
~
Upvotes: 9
Reputation: 2210
You don't have to actually copy the struct into an array of bytes. You could optionally do this:
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));
The power of pointers! :)
Upvotes: 9
Reputation: 16585
It's fairly straightforward: 1. ArrayBuild takes a pointer to a msg_on_send structure, and for each member in there, uses memcpy to copy the bytes into a char array that was passed in like so -
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 is just given a char array and a size - it grabs each char in turn and prints it to the screen as a hex value with printf().
The 'magic' is in the ArrayBuild - memcpy does a literal copy of bytes from source to destination, with no translation. Assuming 4-byte ints, the array built by the function will look like so:
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)
I'd assume that in the 'real' application, the printf() call would be replaced by a call to a serial port write.
Upvotes: 1
Reputation: 425361
Your struct
here is just array of bytes, it contains no pointers that point out of it.
Member-to-member copy is most likely performed to cope with alignment, as (char*) &address
will likely be greater than ((char*) &descriptor_msg) + 5
.
USARTWrite
sends HEX
codes of the bytes of your struct to stdout
, but discards alignment. Compiling this code with different alignment strategies will lead to different outputs.
Enclose your structure declaration into #pragma pack(push, n)
and #pragma pack(pop)
to force alignment, and just copy your structure byte-to-byte.
Upvotes: 0