Reputation: 570
I've been toying around with storing data that will be operated on often into a large array of unsigned char(since C++ does not have a byte type). So, if I store a float into the char array, it will take up the 4 unsigned chars. Simple, except now if I want to edit that data while it is in the array, I would need to access all 4 elements at the same time, which is impossible as far as I know. So, is there a way to edit the 4 unsigned chars into the float value that I desire without resorting to a memcpy()?
Example:
#include <iostream>
#include <string.h>
#include <stdint.h>
using namespace std;
struct testEntity {
float density;
uint16_t xLoc, yLoc;
uint16_t xVel, yVel;
uint16_t xForce, yForce;
uint16_t mass;
uint8_t UId;
uint8_t damage;
uint8_t damageMultiplier;
uint8_t health;
uint8_t damageTaken;
};
int main()
{
testEntity goblin { 1.0, 4, 5, 5, 0, 0, 0, 10, 1, 2, 1, 10, 0 };
testEntity goblin2;
unsigned char datastream[24];
unsigned char* dataPointer = datastream;
memcpy(&datastream, &goblin, sizeof(testEntity));
//I know that datastream[0..3] contains information on goblin.density
//How would I edit goblin.density without memcpy into another testEntity structure?
memcpy(&goblin2, &datastream, sizeof(testEntity));
return 0;
}
Upvotes: 0
Views: 495
Reputation: 36082
by using a union you can access a memory location in various ways, maybe that is what you are looking for (if i understood you correctly):
typedef union
{
struct testEntity
{
float density;
uint16_t xLoc, yLoc;
uint16_t xVel, yVel;
uint16_t xForce, yForce;
uint16_t mass;
uint8_t UId;
uint8_t damage;
uint8_t damageMultiplier;
uint8_t health;
uint8_t damageTaken;
} te;
char datastream[24];
} myunion;
...
myunion goblin = { 1.0, 4, 5, 5, 0, 0, 0, 10, 1, 2, 1, 10, 0 };
char* goblinP = goblin.datastream;
or e.g. goblin.te.health
EDIT:
It would be better to create a serialize/deserialize function for your struct in order to convert it from/to a struct.
e.g.
ostream& operator<<(ostream& o, const testEntity &in)
{
typedef union { float f; char bytes[4]; } floatunion;
floatunion fu = in.density;
o.write( fu.bytes, 4 );
...
return o;
}
Upvotes: 0
Reputation: 141618
Your plan of:
goblinP = (testEntity *)datastream;
violates the strict aliasing rule. Paraphrased , the rule is that an object may only be accessed via an expression with that object's type; with a few exceptions. You can access the object as unsigned chars, but you cannot access unsigned chars as the object.
This code might seem to work but you are really playing with fire, as the compiler may decide to optimize out your attempt to read an object, because the standard says that you are effectively reading an uninitialized variable.
To do what you want, declare your buffer line this:
testEntity goblin;
and then you can alias it as bytes by doing:
unsigned char *datastream = reinterpret_cast<unsigned char *>(&goblin);
You can write bytes through datastream
and then access goblin
to see what you got out. (Of course, this is still subject to the bytes you write in actually being a valid object representation for a testEntity
).
Upvotes: 0
Reputation: 7207
Here's what I did:
#include <iostream>
#include <string.h>
#include <stdint.h>
using namespace std;
struct testEntity {
float density;
uint16_t xLoc, yLoc;
uint16_t xVel, yVel;
uint16_t xForce, yForce;
uint16_t mass;
uint8_t UId;
uint8_t damage;
uint8_t damageMultiplier;
uint8_t health;
uint8_t damageTaken;
};
int main()
{
testEntity goblin = { 1.0, 4, 5, 5, 0, 0, 0, 10, 1, 2, 1, 10, 0 };
testEntity goblin2;
unsigned char datastream[24];
unsigned char* dataPointer = datastream;
testEntity *goblinP;
memcpy(datastream, &goblin, sizeof(testEntity));
goblinP = (testEntity *) datastream;
cout << goblinP->density << endl;
return 0;
}
Upvotes: 1