I'm working on some code, and I have a point where I grab some amount of binary data, then want to extract some bytes from it. So, I have the following:
unsigned char * payload;
int payload_size;
uint32_t major = 0, minor = 0;
payload = out_resp.get_payload(&payload_size); // Retrieve the data, return a pointer
if(payload_size >= 8) { // Need at least 8 bytes in the payload
std::copy(payload, payload + 4, &major);
std::copy(payload + 4, payload + 8, &minor);
}
As you can see, the first four bytes from the payload should be placed in major, and the next four in minor. However, while going through debugging, I'm noticing that after the first std::copy, my variable payload is set to NULL!
Is this expected behavior for std::copy, or is something going wrong? Should I avoid this by simply creating another pointer, and passing that to std::copy?
std::copy doesn't work like memcpy. Your std::copy(payload, payload + 4, &major); will copy:
(&major)[0] = payload[0];
(&major)[1] = payload[1];
(&major)[2] = payload[2];
(&major)[3] = payload[3];
And that's not what you need. (&major)[1] is outside the bounds, so assigning to it causes undefined behavior.
Related
I am trying to access the data that is serialized using boost buffer function and would like to fill it into two vectors. I am having problem with address to fill the second vector. Following class shows the two vectors and how they are filled.
class LidarMeasurement {
private:
std::vector<uint32_t> _header;
std::vector<float> _azimuth;
public:
//The header consists of an array of uint32_t's in the following layout
enum Index : size_t {
HorizontalAngle,
ChannelCount,
SIZE
};
explicit LidarMeasurement(uint32_t NumOfChannels = 0u): _header(Index::SIZE + NumOfChannels, 0u) {
_header[Index::ChannelCount] = NumOfChannels;
}
// called before filling vectors
void Reset(uint32_t total_point_count) {
std::memset(_header.data() + Index::SIZE, 0, sizeof(uint32_t) * GetChannelCount());
_azimuth.clear();
_azimuth.reserve(total_point_count);
}
// after reset,Write point function starts filling vectors.. following function is called 104 times (not constant) before next reset
void WritePoint(uint32_t channel, float angle_hor) {
_header[Index::SIZE + channel] += 1u;
_azimuth.emplace_back(angle_hor);
}
uint32_t GetChannelCount() const {
return _header[Index::ChannelCount];
}
}
Once they are filled, its serialized and sent to a client. its serialized using the function below:
template <typename Sensor>
inline Buffer LidarSerializer::Serialize(
const Sensor &,
const LidarMeasurement &measurement,
Buffer &&output) {
std::array<boost::asio::const_buffer, 2u> seq = {
boost::asio::buffer(measurement._header),
boost::asio::buffer(measurement._azimuth)};
output.copy_from(seq);
return std::move(output);
}
Once I receive the serialized data, I need to put azimuth back to vector.
I am using the following function to get the vector. _begin is the address to the buffer.
std::vector<float> GetAzimuth(const uint32_t* _begin) const{
std::vector<float> localAzimuthMemCopy;
begin_azi = const_cast<float*>(reinterpret_cast<const float*>(_begin )) + (sizeof(uint32_t) * (GetChannelCount() + Index::SIZE));
end_azi = begin_azi + GetTotalPointCount();//Total point count is the addition of individual channel point counts (not shown here)
for(float* i = begin_azi; i < end_azi; i++){
localAzimuthMemCopy.emplace_back(*i);
}
return localAzimuthMemCopy;
}
However, the result i get has a memory offset. I am getting 104 values but the last 18 values are junk. vector is read from a wrong start address. What is wrong with the code?
The problem is caused bt wrong begin adress calculation.
begin_azi = const_cast<float*>(reinterpret_cast<const float*>(_begin )) + (sizeof(uint32_t) * (GetChannelCount() + Index::SIZE));
1) Pointer arithmetic requires only the pointer and number of elements to advance. Number of bytes the compiler should deduct by himself, based on the pointers type. So multiplication at sizeof(uint32_t) is redundant. The correct way of pointer advance is shown at float* end_azi = begin_azi + GetTotalPointCount();
2) Adress offset should be calculated for pointer to uint32_t type, and only then converted to pointer to float type.
So correct way of begin_azi should look this way:
begin_azi = const_cast<float*>(reinterpret_cast<const float*>(_begin + GetChannelCount() + Index::SIZE));
Why did it partially worked earlier? from cppreference
Pointer arithmetic
If the pointer P points at an element of an array with index I, then
P+N and N+P are pointers that point at an element of the same array with index I+N
P-N is a pointer that points at an element of the same array with index {tt|I-N}}
The behavior is defined only if both the original pointer and the result pointer are pointing at elements of the same array or one past the end of that array.
Noone knows where did the pointed begin_azi pointed after wrong calculation. So noone guarantee that the program will execute in correct or wrong way.
Let me explain my problem
First of all, imagine I randomly generated the number "5".
I want to convert this integer to a char* so I can display it using my
Draw_String() method.
I want to have "5" as the central position which would be [1] in a
char* array[2].
In position [0] I want the lower adjacent number "4"
In position [2] I want the higher adjacent number "6"
so
[0] = 4
[1] = 5
[2] = 6
Then I want to display the contents of the vector positions, like this.
4
5
6
However, my output is more like this:
5
5
5
No matter what number I generate, and no matter which operations I perform, I will only get the number "5" in all of my vectors positions.
Code
int startpoint = rand() % 7 + 1;
int assigner = -1;
for (int i = 0; i < 3; i++)
{
startpoint += assigner;
convert = std::to_string(startpoint);
char *converted = &convert[0u];
blocks.push_back(converted);
assigner++;
}
//spin around twice for visual effect.
for (int counter = 0; counter < 2; counter++)
{
Draw_String(drawY, drawX - 1, blocks.at(0));
Draw_String(drawY, drawX, blocks.at(1));
Draw_String(drawY, drawX + 1, blocks.at(2));
}
if anyone could help out I'd appreciate it.
Don't ask me to get rid of char*.
Your code has undefined behavior: it harvests a pointer to the internal string buffer from inside the conver string
char *converted = &convert[0u];
but the buffer can become invalid the next time convert string is re-assigned. The behavior that you see suggests that the buffer gets reused, rather than re-allocated, so the same pointer gets stored in the blocks vector.
The best solution would be to store std::string directly, because it would manage both copying and de-allocation for you:
std::vector<std::string> blocks;
...
blocks.push_back(std::to_string(startpoint));
If you insist on using pointers, make a copy of the string before adding it to the container:
char *copy = new char[strlen(converted)+1];
strcpy(copy, converted);
blocks.push_back(copy);
Now you are required to call delete[] on each element of blocks when you are done in order to avoid memory leaks.
If you needto use char* and not std::string than you need to allocate it and copy content of the string intead of copy the pointer.
instead of:
char *converted = &convert[0u];
use:
char *converted = malloc(convert.length() + 1); // number + '\0'
// can also use char *converted = new char[convert.length() + 1];
strcpy(converted, convert.c_str())
Now, no matter what happens to convert, you have control on your converted data. (take care to also delete it when you don't need it)
Otherwise when convert changes, converted can change or point to invalid data.
This is because in the original implementation converted is pointing to data that is managed by convert object.
I was reading the source of a hashing competition today, and came across this:
#define BYTES_IN_BLOCK 1024
struct block{
uint8_t v[BYTES_IN_BLOCK];
block(){ memset(v, 0, BYTES_IN_BLOCK); }
uint64_t& operator[](uint8_t i){ return *(uint64_t*)(v + 8 * i); }
};
Then, a little later in the code, there's this:
state = new block[cost]; // cost is a uint32_t (like 1024)
// Probably 50 lines of code.
block prev_block;
prev_block = state[foo]; // foo is a uint32_t
What I can't figure out is what this is doing. Now, I understand C, but C++ not so much. Bear with me here for a second.
This part: return *(uint64_t*)(v+8*i) should return a uint64_t, and does so when I tested it:
state->v[8*10] = 12;
uint64_t bar = *(uint64_t*)(v+8*10);
printf("%" PRIu64 "\n", bar);
So that all makes sense.
But this:
prev_block = state[foo];
Makes no sense. Since state is block*, prev_block should now "be" state, correct? But it doesn't, because their arrays are different.
state->v[8*12] = 12;
printf("%" PRIu64 "\n", (*state)[12]);
prev_block = state[12];
printf("%" PRIu64 "\n", (*(&prev_block))[12]);
So, what exactly is going on here?
You are mixing up the two operator[]s involved here. In your last example, you set state[0][12] = 12, and you're comparing it to state[12][12]. Since state is a block*, state[n] is just normal array access; it doesn't invoke the operator[] defined in block.
state = new block[cost];
prev_block = state[foo];
is analogous to:
int* arr = new int[size];
int a = arr[index];
That's basic C++. I am not sure why that is confusing.
There is confusion with a number of concepts here. I'm going to blast through all the ones I see because they are all important, not just the immediate answer.
state is a pointer to block, but state[0] should just be a block, specifically the first block in state and also the result of *state.
prev_block = state[foo];
All of the data in block is simple, just a self-contained array of bytes, so it should be directly copy-able without any special assistance. prev_block = state[foo] should copy state[foo] to prev_block. Since it's a copy, the addressing will be different.
In the printout code provided:
state->v[8*12] = 12;
Breaking his down for clarity. state-> is going to access the first element of the state array. state->v[8*12] is going to access v[8*12] of state[0]. state->v[8*12] = 12; is going to set v[8*12] of state[0]to 12. This means byte 96 of v is going to be 12. To reference a different state you can use (state + array_index)->v[8*12]; or state[array_index].v[8*12]; I find the latter more readable.
printf("%" PRIu64 "\n", (*state)[12]);
(*state) gives you the first state in the array, AKA state[0]. (*state)[12] uses state[0]'s [] operator, defined as uint64_t& operator[](uint8_t i){ return *(uint64_t*)(v + 8 * i); }
This is going to return a 64 bit int starting at the address of state[0].v[12*8] and comprised of the next 8 bytes of array v (v[96] through v[103], resulting in 12,0,0,0,0,0,0,0). This will be 12 or a god-awful big number depending on the system's endian. The wrapping printf is going to print the returned number.
prev_block = state[12];
Is going to copy the 13th element of the state array to prev_block, assuming enough blocks were created by state = new block[cost];. Nothing magical, but there shouldn't be anything there but zeros because the only state that has any values set is state[0]. You either wanted to copy state[0] here or write to state[12] up a few lines.
printf("%" PRIu64 "\n", (*(&prev_block))[12]);
the * and & cancel each other out before accomplishing anything. It will then print out the result of using the block [] operator as above. Should be zero.
I have a class that parses some incoming serial data. After the parsing a method should return a byte array with some of the parsed data. The incoming data is of unknown length so my return array will always be different.
So far my method allocates an array bigger than what I need to return and fills it up with my data bytes and I keep an index so that I know how much data I put in the byte array. My problem is that I don't know how to return this from an instance method.
void HEXParser::getParsedData()
{
byte data[HEX_PARSER_MAX_DATA_SIZE];
int dataIndex = 0;
// fetch data, do stuff
// etc, etc...
data[dataIndex] = incomingByte;
_dataIndex++;
// At the very end of the method I know that all the bytes I need to return
// are stored in data, and the data size is dataIndex - 1
}
On other languages this is trivial to do but I'm not very proficient in C++ and I'm completely stuck.
Thanks!
You are working on a microcontroller with just a little bit of RAM. You need to carefully evaluate if "unknown length" also implies unbounded length. You cannot deal with unbounded length. Your best approach for reliable operation is to use fixed buffers setup for the maximum size.
A common pattern for this type of action is to pass the buffer to the function, and return what has been used. Your function would then look much like many of the C character string functions:
const size_t HEX_PARSER_MAX_DATA_SIZE = 20;
byte data[HEX_PARSER_MAX_DATA_SIZE];
n = oHexP.getParsedData(data, HEX_PARSER_MAX_DATA_SIZE);
int HEXParser::getParsedData(byte* data, size_t sizeData)
{
int dataIndex = 0;
// fetch data, do stuff
// etc, etc...
data[dataIndex] = incomingByte;
dataIndex++;
if (dataIndex >= sizeData) {
// stop
}
// At the very end of the method I know that all the bytes I need to return
// are stored in data, and the data size is dataIndex - 1
return dataIndex;
}
I have been writing some code to create a byte array I will be sending over a socket to another process. However noticed some really odd behavior regarding my byte[].
The cout at the end prints out 99, however looking at my code, I couldn't find where the value is being set. I create a char array of size sendingSize which is a constant. I don't set the value 307200* 3 so I don't understand how it prints out with a value...
char tosend[sendingSize];
//Send over the frame
for(int i = 0; i < 307200; i++)
{
tosend[i * 3] = (byte)imCopy[i/640][i%640].red;
tosend[i * 3+1] = (byte)imCopy[i/640][i%640].green;
tosend[i * 3+2] = (byte)imCopy[i/640][i%640].blue;
}
char *bytePointer = tosend;
cout<<(int)tosend[307200* 3]<<endl;
Your code does not write any value into index 307200*3 (because the highest index your for loop reaches is 307199). So you are reading some byte from memory beyond the declared size of your array. This is undefined behaviour and anything could happen.
Some other programming languages (such as Java) do automatic range checking on arrays and would throw an exception in this case. In C++, you are expected to do the right thing and the compiler doesn't generate range checking code for you.