I'm baffled. I have an identical program being uploaded to two different Arduino boards. It's in C++.
It's a much larger program, but I'm cutting it down to only the problematic part. Basically, I have a "host" Arduino and a "rover" Arduino communicating wirelessly. There are multiple rover units, but the problem is only happening on one of them. The rovers have motors that need to be calibrated, so I have static variables in my Motor namespace to hold those calibration values. To prevent having to change these values in the source code, recompile and reupload every time I want to calibrate it, I'm using the wireless system to allow the host to send calibration values to the rover at runtime.
Here's the problem: on one rover, the values aren't being updated if I call the ChangeSpeed method, but they do get updated if I modify the variables directly.
Let me stress that it works fine on four out of five rovers. The problem is happening on exactly one rover. The code being uploaded to each rover is identical.
The following code is causing a problem:
Motor.h:
namespace Motor
{
static unsigned char left_speed = 0;
static unsigned char right_speed = 0;
void ChangeSpeed(unsigned char, unsigned char);
}
Motor.cpp:
void Motor::ChangeSpeed(unsigned char l_speed, unsigned char r_speed)
{
left_speed = l_speed;
right_speed = r_speed;
soft.println("Change speed: " + String(left_speed) + ", " + String(right_speed));
}
Main.cpp:
void UpdateSpeedValuesBad(unsigned char l_speed, unsigned char r_speed)
{
Motor::ChangeSpeed(l_speed, r_speed);
soft.println("Motor write: " + String(l_speed) + ", " + String(r_speed));
}
void UpdateSpeedValuesGood(unsigned char l_speed, unsigned char r_speed)
{
Motor::left_speed = l_speed;
Motor::right_speed = r_speed;
soft.println("Motor write: " + String(l_speed) + ", " + String(r_speed));
}
void ReturnSpeedValues()
{
soft.println("Motor read: " + String(Motor::left_speed) + ", " + String(Motor::right_speed));
}
Case 1:
On the bad rover, the host invokes UpdateSpeedValuesBad(5, 5), and then invokes ReturnSpeedValues. The output is:
Change speed: 5, 5
Motor write: 5, 5
Motor read: 0, 0
Case 2:
On the bad rover, the host invokes UpdateSpeedValuesGood(5, 5), and then invokes ReturnSpeedValues. The output is:
Motor write: 5, 5
Motor read: 5, 5
Case 3:
On a good rover, the host invokes UpdateSpeedValuesBad(5, 5), and then invokes ReturnSpeedValues. The output is:
Change speed: 5, 5
Motor write: 5, 5
Motor read: 5, 5
Am I doing something fundamentally wrong? I come from a C# background so C++ is pretty alien to me. I have no idea if I'm doing something that has undefined behaviour.
Edit: If I shove everything into one single file, it works fine. It only fails once I split it up across a header file and a cpp file.
Main.cpp:
#include <SoftwareSerial.h>
SoftwareSerial soft(9, 10);
namespace Motor
{
static int left_speed = 0;
void ChangeSpeed(unsigned char);
}
void Motor::ChangeSpeed(unsigned char l_speed)
{
left_speed = l_speed;
soft.println("Change speed: " + String(left_speed));
}
void setup()
{
soft.begin(9600);
soft.println("Before: " + String(Motor::left_speed));
Motor::ChangeSpeed(5);
soft.println("Bad attempt: " + String(Motor::left_speed));
Motor::left_speed = 5;
soft.println("Good attempt: " + String(Motor::left_speed));
}
void loop()
{
}
Output:
Before: 0
Change speed: 5
Bad attempt: 5
Good attempt: 5
Edit 2: I dove into the assembly and found this for the bad case. It's using different memory addresses based on whether I call ChangeSpeed or I update the values directly. Anyone know why that would be? Is it a compiler bug or is it not guaranteed that the addresses will be the same?
000000a8 <setup>:
{
Motor::ChangeSpeed(5, 6);
a8: 85 e0 ldi r24, 0x05 ; 5
aa: 66 e0 ldi r22, 0x06 ; 6
ac: 0e 94 5f 00 call 0xbe ; 0xbe <_ZN5Motor11ChangeSpeedEhh>
Motor::left_speed = 5;
b0: 85 e0 ldi r24, 0x05 ; 5
b2: 80 93 00 01 sts 0x0100, r24
Motor::right_speed = 6;
b6: 86 e0 ldi r24, 0x06 ; 6
b8: 80 93 01 01 sts 0x0101, r24
}
bc: 08 95 ret
000000be <_ZN5Motor11ChangeSpeedEhh>:
void Motor::ChangeSpeed( unsigned char l_speed, unsigned char r_speed )
{
left_speed = l_speed;
be: 80 93 02 01 sts 0x0102, r24
right_speed = r_speed;
c2: 60 93 03 01 sts 0x0103, r22
c6: 08 95 ret
You should not make these variables static. A static global variable means the variable is local to the compilation unit (generally, the .cpp file that is being compiled) so if you have the static variable declared in a header file and include that header file in 3 different .cpp files that are compiled separately then you will have 3 independent versions of that variable, one for each .cpp file.
Instead, in the header file declare them as
namespace Motor {
extern unsigned char left_speed;
extern unsigned char right_speed;
void ChangeSpeed(unsigned char, unsigned char);
}
This tells the compiler that some file will provide a definition for these variables and to use that common shared definition.
Then, since the variables need to be defined exactly once (this is called the one definition rule) you should add the definition to Motor.cpp:
unsigned char Motor::left_speed = 0;
unsigned char Motor::right_speed = 0;
I chose Motor.cpp to hold the definition since this is where the definition of the ChangeSpeed function is.
In C++, the static keyword works much differently than in C#. It might be somewhat similar when used inside a class definition, but that is where the similarities end.
By declaring the variables static, you limit their range to the current code unit. In other words, by having static variables in your .h, you cause Motor.cpp and Main.cpp to have separate copies of those two variables.
Your case 1 modifies the Motor.cpp copies of those variables while outputs the ones from Main.cpp. Case 2 works only on Main.cpp copies so it works as expected. And if you shove everything into a single file, you just get one copy of those variables.
You should either:
Declare the variables as extern unsigned char left_speed, right_speed; in the header, and then declare the values as unsigned char left_speed = 0; in one of the .cpp files;
Declare the static variables in one of the .cpp files directly (e.g. Rotor.cpp) and use functions to get their values like you use one to set them.
Related
Will wrapping a protobuf parameter in a separate message give any extra runtime overhead?
This:
message MyData {
optional uint32 data = 1;
}
message Container {
optional MyData data = 1;
}
vs.
message Container {
optional uint32 data = 1;
}
I'm only using the C++ implementation if that matters.
Extra wire overhead? Serialization overhead? Access overhead?
There is a overhead for every embedded message as per encoding explanation of protobufs
Below simple message with one int value would be encoded as 08 96 01
message Test1 {
required int32 a = 1;
}
Meanwhile encoding of message definition with an embedded message would look like 1a 03 08 96 01
Test1:
message Test3 {
required Test1 c = 3;
}
Documentation explains it saying that
the last three bytes are exactly the same as our first example (08 96 01), and they're preceded by the number 3 – embedded messages are treated in exactly the same way as strings (wire type = 2).
So in short 1a 03 is added as overhead into Test3 since Test1 is another message type
Basically, I'm building some code in which an array of objects (I've made the object myself) need to be accessible class wide, but initialized after some other steps. This is what I've made:
The base object
unsigned char stepPin;
unsigned char dirPin;
unsigned char sensorPin;
const char* ident;
//Object
StepperMotor :: StepperMotor(const unsigned char _stepPin,
const unsigned char _dirPin,
const unsigned char _sensorPin,
const char* _ident)
{
stepPin = _stepPin;
dirPin = _dirPin;
sensorPin = _sensorPin;
ident = _ident;
std::cout << "Motor " << ident << ": Step Pin - " << (int)stepPin << " | Direction Pin - " << (int)dirPin << std::endl;
}
The object manager
#include "stepperMotor.h"
#include <iostream>
#include <wiringPi.h>
#include <thread>
#include <cstdlib>
#include <vector>
#include "stepperManager.h"
StepperMotor motors[] = {
{7, 15, 16, "HS"},
{0, 1, 2, "HL"},
{3, 4, 5, "HP"},
{12, 13, 6, "CS"},
{14, 10, 11, "VP"},
{21, 22, 26, "TC"},
{23, 24, 27, "TR"},
{25, 28, 29, "IN"}
};
StepperManager::StepperManager()
{
for (int i = 0; i < 8; i++){
motors[i].dumpData();
}
}
Now to the actual problem...
After the initial declaration, all the elements in the array become the last element. You can see this by looking at the output when it's run:
Output:
Motor HS: Step Pin - 7 | Direction Pin - 15
Motor HL: Step Pin - 0 | Direction Pin - 1
Motor HP: Step Pin - 3 | Direction Pin - 4
Motor CS: Step Pin - 12 | Direction Pin - 13
Motor VP: Step Pin - 14 | Direction Pin - 10
Motor TC: Step Pin - 21 | Direction Pin - 22
Motor TR: Step Pin - 23 | Direction Pin - 24
Motor IN: Step Pin - 25 | Direction Pin - 28
Declare the motor man
Motor IN: Step Pin - 25 | Direction Pin - 28
Motor IN: Step Pin - 25 | Direction Pin - 28
Motor IN: Step Pin - 25 | Direction Pin - 28
Motor IN: Step Pin - 25 | Direction Pin - 28
Motor IN: Step Pin - 25 | Direction Pin - 28
Motor IN: Step Pin - 25 | Direction Pin - 28
Motor IN: Step Pin - 25 | Direction Pin - 28
Motor IN: Step Pin - 25 | Direction Pin - 28
So, I don't fully understand why this is happening, I've tried making the array static, and switching to vectors instead, but none of it has helped. I'm afraid that I just don't know enough about the language to find the issue on my own.
EDIT
It was pointed out that I missed the actual run code. Sorry about that guys.
This is the "main" file that implements the objects.
#include <iostream> // For cout and cerr
#include <cstdlib> // For atoi()
#include <cstring>
#include "stepperManager.h"
int main(int argc, char **argv)
{
std::cout << "Declare the motor man" << std::endl;
StepperManager motorMan;
return 0;
}
Here you want to learn a bit more about classes and how they work. In StepperMotor's source file, you're defining file-scope global variables with external linkage. Every time you construct a StepperMotor, you're overwriting those same variables, so all StepperMotors are effectively accessing the same values (and hence the behavior you're seeing).
Since you have a C# background, it's like you're using static member variables for StepperMotors here. You want non-static member variables. Simple example:
Foo.h:
// Foo.h
#ifndef FOO_H
#define FOO_H
class Foo
{
public:
explicit Foo(int value);
void print_value() const;
private:
int member_variable;
}
#endif
Foo.cpp:
// Foo.cpp
#include "Foo.h"
#include <iostream>
using namespace std;
Foo::Foo(int value): member_variable(value)
{
}
void Foo::print_value() const
{
cout << member_variable << endl;
}
main.cpp:
// main.cpp
#include "Foo.h"
int main()
{
Foo f1(123);
Foo f2(456);
Foo f3(789);
f1.print_value();
f2.print_value();
f3.print_value();
}
Output:
123
456
789
Also I see some thread usage in your example. I'd suggest, at this point, that this is like juggling razor blades. You want to kind of stick to the basics first, get the hang of the language, debugger, and then you can babystep your way towards parallelizing execution, micro-tuning with a profiler in hand, etc.
You've declared four global variables, which you change every time a StepperMotor is created. Instead, you want these to be class members, so that each object has its own copy of them, independent of those in other objects:
class StepperMotor {
unsigned char stepPin;
unsigned char dirPin;
unsigned char sensorPin;
const char* ident;
// and constructors, member functions, etc.
};
I think there should be something like this in your steppermotor.h
class StepperMotor{
//some more stuff
public:
unsigned char stepPin;
unsigned char dirPin;
unsigned char sensorPin;
const char* ident;
unsigned int stepVal;
}
This is how member variables are declared in c++.
I think it might be usefull though to read some c++ tutorial, to learn the basics.
In a header file, I declare a struct with an array and array length like so:
typedef struct {
unsigned char *frame;
int length;
} ResponseFrame ;
extern ResponseFrame rf;
In my main file, I have the following:
ResponseFrame rf;
int main(void)
{
while(1) {
if (receive() == 0x01) {
uint8_t val;
rf.length = 6;
for(int i = 0; i < 6; i++){
val = receive();
rf.frame[i] = val;
transmit(val); // LINE 1
}
for (uint8_t i=0; i<rf.length; i++){
transmit(rf.frame[i]); // LINE 2
}
}
}
}
The array I'm receiving is
{ 00 00 FF 00 FF 00 }
The initial transmit responds with this received data [see LINE 1] .
However, when I try to transmit using the global variable rf.frame [see LINE 2], the first value is different like this ----
{ 13 00 FF 00 FF 00 }
Why is that first initial value different like this??
You never allocate any memory for ResponseFrame.frame, so you're running into undefined behaviour.
You're assuming that by doing rf.length = 6;, the size of unsigned char *frame; somehow magically increases, but it doesn't.
If you're certain of the size, you need:
rf.length = 6;
rf.frame = malloc(sizeof(unsigned char) * 6); //for C
or use a std::vector in C++.
Part of the problem might be that it appears to be relying on undefined behavior. It appears (from the shown code) that frame is never initialized. If it is a fixed size, it could be declared as:
unsigned char frame[6];
Otherwise, it may need a call to malloc to allocate memory for it.
I have a class that represents some file data. The file contains some headers.
Within the class definition I also have a template method that looks like this
template< typename T>
T Get(int offset)
{
return *((T*)(_data + offset)); // where _data is a member variable. unsigned char*
}
So for example, if I want to read a particular field of the header I can simply call the get method.
i.e.
uint64 GetCRC64()
{
return Get(1);
}
However, the trouble I'm having is that it doesn't appear to be writing the data as expected.
template <typename T>
void Set(int offset, T value)
{
*((T*)(_data + offset)) = value; // where _data is a member variable. void*
}
As I write _data to a file. Using a hex editor the file seems to be wrong.
Now, before you ask yes I am aware that it's sensitive to endianess. However this code will only ever be run on the intel platform. So always little endian.
The header looks like this:
1byte - version
8 byte - crc64
8 byte - serial number
So if I had a version number 1 and a crc = 0x001122334455667788 and serial number 1 I would expect it to look like this in the written file.
01 00 11 22 33 44 55 66 77 88 00 00 00 00 00 00 00 01
But instead I see something like:
01 00 00 00 00 00 00 00 00 00 11 22 33 44 55 66 77 88
Again this is from memory but it seems to be writing the data at the wrong offset.
I'll be able update this post with the exact data being written and read and the hex output in a few hours.
The offsets I am using for Set are 0 (version), 1 (crc) & 9(serial #). I think it's to do with Get/Set. But I don't quite see why. Maybe someone can spot why it isn't working quite as expected.
I think this example illustrates the problem I'm having better. Any idea why it doesn't print out the value fed in by hand?
#include <stdio.h>
#include <stdlib.h>
struct Test
{
Test()
{
_data = new unsigned char[100];
// Fill _data with known data
// first byte is 1
_data[0] = 1;
// Next 8 bytes are 0x0102030405060708
_data[1] = 0x01;
_data[2] = 0x02;
_data[3] = 0x03;
_data[4] = 0x04;
_data[5] = 0x05;
_data[6] = 0x06;
_data[7] = 0x07;
_data[8] = 0x08;
_data[9] = 0x0A;
_data[10] = 0x0B;
_data[11] = 0x0C;
_data[12] = 0x0D;
_data[13] = 0x0E;
_data[14] = 0x0F;
_data[15] = 0x0A;
_data[16] = 0x0B;
}
template <typename T> T & val(size_t offset) { return *(reinterpret_cast<T*>(_data) + offset); }
template <typename T> const T & val(size_t offset) const { return *(reinterpret_cast<T*>(_data) + offset); }
unsigned char* _data;
};
int main(int argc, char* argv[])
{
Test t;
printf("t(0)=0x%X\n", t.val<char>(0));
printf("t(1)=0x%llX\n", t.val<unsigned long long>(1));
printf("t(9)=0x%llX\n", t.val<unsigned long long>(9));
}
Your casts are wrong. You can only do arithmetic on pointers to complete types. Try it like this:
T * const p = reinterpret_cast<T*>(_data);
return *(p + offset);
// or
*(p + offset) = value;
Speaking of, why not implement a single val() accessor for both reading and writing?
T & val(size_t offset) { return *(reinterpret_cast<T*>(_data) + offset); }
const T & val(size_t offset) const { return *(reinterpret_cast<T*>(_data) + offset); }
I am trying to debug why my TCP transfers are corrupted when sent from Cygwin. I see that only the first 24 bytes of each structure are showing up in my server program running on Centos. The 25th through 28th bytes are scrambled and all others after that are zeroed out. Going in the other direction, receiving from Centos on Cygwin, again only the first 24 bytes of each block are showing up in my server program running on Cygwin. The 25th through 40th bytes are scrambled and all others after that are zeroed out. I also see the issue when sending or receiving to/from localhost on Cygwin. For localhost, the first 34 bytes are correct and all after that are zeroed out.
The application I am working on work fine on Centos4 talking to Centos and I am trying to port it to Cygwin. Valgrind reports no issues on Centos, I do not have Valgrind running on Cygwin. Both platforms are little-endian x86.
I've run Wireshark on the host Windows XP system under which Cygwin is running. When I sniff the packets with Wireshark they look perfect, for both sent packets from Cygwin and received packets to Cygwin.
Somehow, the data is corrupted between the level Wireshark looks at and the program itself.
The C++ code uses ::write(fd, buffer, size) and ::read(fd, buffer, size) to write and read the TCP packets where fd is a file descriptor for the socket that is opened between the client and server. This code works perfectly on Centos4 talking to Centos.
The strangest thing to me is that the packet sniffer shows the correct complete packet for all cases, yet the cygwin application never reads the complete packet or in the other direction, the Centos application never reads the complete packet.
Can anyone suggest how I might go about debugging this?
Here is some requested code:
size_t
read_buf(int fd, char *buf, size_t count, bool &eof, bool immediate)
{
if (count > SSIZE_MAX) {
throw;
}
size_t want = count;
size_t got = 0;
fd_set readFdSet;
int fdMaxPlus1 = fd + 1;
FD_ZERO(&readFdSet);
FD_SET(fd, &readFdSet);
while (got < want) {
errno = 0;
struct timeval timeVal;
const int timeoutSeconds = 60;
timeVal.tv_usec = 0;
timeVal.tv_sec = immediate ? 0 : timeoutSeconds;
int selectReturn = ::select(fdMaxPlus1, &readFdSet, NULL, NULL, &timeVal);
if (selectReturn < 0) {
throw;
}
if (selectReturn == 0 || !FD_ISSET(fd, &readFdSet)) {
throw;
}
errno = 0;
// Read buffer of length count.
ssize_t result = ::read(fd, buf, want - got);
if (result < 0) {
throw;
} else {
if (result != 0) {
// Not an error, increment the byte counter 'got' & the read pointer,
// buf.
got += result;
buf += result;
} else { // EOF because zero result from read.
eof = true;
break;
}
}
}
return got;
}
I've discovered more about this failure. The C++ class where the packet is being read into is laid out like this:
unsigned char _array[28];
long long _sequence;
unsigned char _type;
unsigned char _num;
short _size;
Apparently, the long long is getting scrambled with the four bytes that follow.
The C++ memory sent by Centos application, starting with _sequence, in hex, looks like this going to write():
_sequence: 45 44 35 44 33 34 43 45
_type: 05
_num: 33
_size: 02 71
Wireshark shows the memory laid out in network big-endian format like this in the packet:
_sequence: 45 43 34 33 44 35 44 45
_type: 05
_num: 33
_size: 71 02
But, after read() in the C++ cygwin little-endian application, it looks like this:
_sequence: 02 71 33 05 45 44 35 44
_type: 00
_num: 00
_size: 00 00
I'm stumped as to how this is occurring. It seems to be an issue with big-endian and little-endian, but the two platforms are both little-endian.
Here _array is 7 ints instead of 28 chars.
Complete memory dump at sender:
_array[0]: 70 a2 b7 cf
_array[1]: 9b 89 41 2c
_array[2]: aa e9 15 76
_array[3]: 9e 09 b6 e2
_array[4]: 85 49 08 81
_array[5]: bd d7 9b 1e
_array[6]: f2 52 df db
_sequence: 41 41 31 35 32 43 38 45
_type: 05
_num: 45
_size: 02 71
And at receipt:
_array[0]: 70 a2 b7 cf
_array[1]: 9b 89 41 2c
_array[2]: aa e9 15 76
_array[3]: 9e 09 b6 e2
_array[4]: 85 49 08 81
_array[5]: bd d7 9b 1e
_array[6]: f2 52 df db
_sequence: 02 71 45 05 41 41 31 35
_type: 0
_num: 0
_size: 0
Cygwin test result:
4
8
48
0x22be08
0x22be28
0x22be31
0x22be32
0x22be38
Centos test result:
4
8
40
0xbfffe010
0xbfffe02c
0xbfffe035
0xbfffe036
0xbfffe038
Now that you've shown the data, your problem is clear. You're not controlling the alignment of your struct, so the compiler is automatically putting the 8 byte field (the long long) on an 8 byte boundary (offset 32) from the start of the struct, leaving 4 bytes of padding.
Change the alignment to 1 byte and everything should resolve. Here's the snippet you need:
__attribute__ ((aligned (1))) __attribute ((packed))
I also suggest that you use the fixed-size types for structures being blitted across the network, e.g. uint8_t, uint32_t, uint64_t
Previous thoughts:
With TCP, you don't read and write packets. You read and write from a stream of bytes. Packets are used to carry these bytes, but boundaries are not preserved.
Your code looks like it deals with this reasonably well, you might want to update the wording of your question.
Hopefully final update :-)
Based on your latest update, Centos is packing your structures at the byte level whilst CygWin is not. This causes alignment problems. I'm not sure why the CygWin-to-CygWin case is having problems since the padding should be identical there but I can tell you how to fix the other case.
Using the code I gave earlier:
#include <stdio.h>
typedef struct {
unsigned char _array[28];
long long _sequence;
unsigned char _type;
unsigned char _num;
short _size;
} tType;
int main (void) {
tType t[2];
printf ("%d\n", sizeof(long));
printf ("%d\n", sizeof(long long));
printf ("%d\n", sizeof(tType));
printf ("%p\n", &(t[0]._array));
printf ("%p\n", &(t[0]._sequence));
printf ("%p\n", &(t[0]._num));
printf ("%p\n", &(t[0]._size));
printf ("%p\n", &(t[1]));
return 0;
}
If you don't want any padding, you have two choices. The first is to re-organise your structure to put the more restrictive types up front:
typedef struct {
long long _sequence;
short _size;
unsigned char _array[28];
unsigned char _type;
unsigned char _num;
} tType;
which gives you:
4
8
40
0x22cd42
0x22cd38
0x22cd5f
0x22cd40
0x22cd60
In other words, each structure is exactly 40 bytes (8 for sequence, 2 for size, 28 for array and 1 each for type and num). But this may not be possible if you want it in a specific order.
In that case, you can force the alignments to be on a byte level with:
typedef struct {
unsigned char _array[28];
long long _sequence;
unsigned char _type;
unsigned char _num;
short _size;
} __attribute__ ((aligned(1),packed)) tType;
The aligned(1) sets it to byte alignment but that won't affect much since objects don't like having their alignments reduced. To force that, you need to use packed as well.
Doing that gives you:
4
8
40
0x22cd3c
0x22cd58
0x22cd61
0x22cd62
0x22cd64
Earlier history for prosperity:
Well, since I wget and ftp huge files just fine from CygWin, my psychic debugging skills tell me it's more likely to be a problem with your code rather than the CygWin software.
In other words, regarding the sentence "the packets are corrupted between the level Wireshark looks at and the program itself", I'd be seriously looking towards the upper end of that scale rather than the lower end :-)
Usually, it's the case that you've assumed a read will get the whole packet that was sent rather than bits at a time but, without seeing the code in question, that's a pretty wild guess.
Make sure you're checking the return value from read to see how many bytes are actually being received. Beyond that, post the code responsible for the read so we can give a more in-depth analysis.
Based on your posted code, it looks okay. The only thing I can suggest is that you check that the buffers you're passing in are big enough and, even if they are, make sure you print them immediately after return in case some other piece of code is corrupting the data.
In fact, in re-reading your question more closely, I'm a little confused. You state you have the same problem with your server code on both Linux and CygWin yet say it's working on Centos.
My only advice at this point is to put debugging printf statements in that function you've shown, such as after the select and read calls to output the relevant variables, including got and buf after changing them, and also in every code path so you can see what it's doing. And also dump the entire structure byte-for-byte at the sending end.
This will hopefully show you immediately where the problem lies, especially since you seem to have data showing up in the wrong place.
And make sure your types are compatible at both ends. By that, I mean if long long is different sizes on the two platforms, your data will be misaligned.
Okay, checking alignments at both ends, compile and run this program on both systems:
#include <stdio.h>
typedef struct {
unsigned char _array[28];
long long _sequence;
unsigned char _type;
unsigned char _num;
short _size;
} tType;
int main (void) {
tType t[2];
printf ("%d\n", sizeof(long));
printf ("%d\n", sizeof(long long));
printf ("%d\n", sizeof(tType));
printf ("%p\n", &(t[0]._array));
printf ("%p\n", &(t[0]._sequence));
printf ("%p\n", &(t[0]._num));
printf ("%p\n", &(t[0]._size));
printf ("%p\n", &(t[1]));
return 0;
}
On my CygWin, I get:
4 long size
8 long long size
48 structure size
0x22cd30 _array start (size = 28, padded to 32)
0x22cd50 _sequence start (size = 8, padded to 9???)
0x22cd59 _type start (size = 1)
0x22cd5a _size start (size = 2, padded to 6 for long long alignment).
0x22cd60 next array element.
The only odd bit there is the padding before _type but that's certainly valid though unexpected.
Check the output from Centos to see if it's incompatible. However, your statement that CygWin-to-CygWin doesn't work is incongruous with that possibility since the alinments and sizes would be compatible (unless your sending and receiving code is compiled differently).