Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Struct to Byte array

Status
Not open for further replies.

MarkLaz

Technical User
May 20, 2005
12
GB
Hello all,

A relatively simple question I hope. I would like to convert a structure to a byte array, I thought the best way to do it would be by either incrementing a byte pointer for the start of the struct and writing it in, within a loop.

Am I barking up the wrong tree? Is there a function which will accomplish the same, but simpler?

Thanks in advance,

Mark
 
> I would like to convert a structure to a byte array
What sort of structure?

What do you intend to do with the byte array once you've got it (store in a file, send over the network) ?



--
 
As Salem said, what do you intend to do with it. If you are sending it to another machine with a different architecture eg big endian vs little endian, it probably won't work when you reconstruct it.
 
Salem, xwb,

I'm writing an interface to a programmable logic controller that sits in a slot on the pci bus of a pc. At it has to maintain a safety factor above and beyond that provided by a PC it has a seperate power supply (also plugged into a PCI slot). As such, it has a relatively convoluted technology specific interface which allows reads/writes to a shared memory area on the PLC.

The PLC does indeed need the byte conversion, although I have done this previously in my code and just need to send the struct holding my data to the PLC, accessing this memory area. The simplest way is by writing the data byte by byte to a respectively incrementing memory address on the PLC - it's a simple task for me to write the PLC code to reconvert to a struct on the other side.

As I'm sure you've guessed, PLC code is my strong point, not C++! I really just need to be able to convert a struct into a byte array, if I could do it byte by byte (and therefore do my write to the memory area at the same time) I think this would be the best solution. Any help with this (headers to include, baby steps to take) is much appreciated. I hope this is enough information, thanks for your interest...

Mark

PS
I'll have to do the same in reverse for reads, I imagine this will be a relatively simple inverse operation?
 
Some code, then words
Code:
#include <iostream>
#include <iomanip>
using namespace std;

// The holes between members of the structure
// are implementation specific, as are the
// contents of those holes when you fill in
// a struct.
struct foo {
  char  a;
  int   b;
};

// You can try and squeeze out the holes, but
// how you ask the compiler to do this is
// compiler specific
#pragma pack(1)
struct bar {
  char  a;
  int   b;
};

// A little something to show all the bytes
void dumpHex ( void *p, size_t size ) {
  unsigned char *bytes = (unsigned char *)p;
  for ( size_t i = 0 ; i < size ; i++ ) {
    unsigned int b = bytes[i];
    cout << setw(2) << setbase(16) << b << " ";
  }
  cout << endl;
}

// Just one way of packing a struct
size_t packFoo ( foo v1, unsigned char *ba ) {
  size_t  used = 0;
  memmove ( &ba[used], &v1.a, sizeof v1.a );
  used += sizeof v1.a;
  memmove ( &ba[used], &v1.b, sizeof v1.b );
  used += sizeof v1.b;
  return used;
}
size_t packBar ( bar v1, unsigned char *ba ) {
  size_t  used = 0;
  memmove ( &ba[used], &v1.a, sizeof v1.a );
  used += sizeof v1.a;
  memmove ( &ba[used], &v1.b, sizeof v1.b );
  used += sizeof v1.b;
  return used;
}
void packdemo ( foo &v1, bar &v2 ) {
  unsigned char b1[sizeof(foo)];  // worst-case, it packs into its
  unsigned char b2[sizeof(bar)];  // own size.

  size_t s1 = packFoo( v1, b1 );
  size_t s2 = packBar( v2, b2 );

  cout << "Packed size of foo is " << s1 << endl;
  dumpHex ( b1, s1 );
  // expect nothing here, the #pragma pack(1) had done
  // all the work
  cout << "Packed size of bar is " << s2 << endl;
  dumpHex ( b2, s2 );
}

int main ( ) {
  foo v1 = { 'a', 0x1234 };
  bar v2 = { 'a', 0x1234 };
  cout << "size of foo " << sizeof(foo) << endl;
  dumpHex ( &v1, sizeof v1 );
  cout << "size of bar " << sizeof(bar) << endl;
  dumpHex ( &v2, sizeof v2 );
  packdemo(v1,v2);
  return 0;
}


My output
$ ./a.out
size of foo 8
61 9c 54  0 34 12  0  0
size of bar 5
61 34 12  0  0
Packed size of foo is 5
61 34 12  0  0
Packed size of bar is 5
61 34 12  0  0
This demonstrates
- That struct foo has holes, because the total size is larger than the sum of sizes of it's members
- That the holes contain junk (9c, 54, 00) in this test
- Using a compiler directive to squeeze out the holes.
- A technique for copying data from a struct to a byte array which squeezes out holes. This doesn't fix the endian problem (though it could be extended to do this).

Consequences of using #pragma pack(1)
- The code isn't portable, not all compilers support packing, and not all compilers ask for packing in the same way.
- There may be a performance penalty every time you access the struct. After all, the padding was added in the first place to maximise the performance of struct accesses.

Which OS is running on the PC?
None of the NT-class operating systems will allow you to directly access the hardware unless that code is running as a driver. For this, you would need


> The simplest way is by writing the data byte by byte to a respectively incrementing memory address on the PLC
In it's simplest form, you could just do
[tt] memcpy ( PLCMemoryPtr, &v1, sizeof v1 );[/tt]
But then all the packing and endian problems would need to be sorted out on the PLC side.

I guess it boils down to which side do you want to do the work on.

--
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top