C++ update structure offset - c++

when i trying make function to set meshes, then i got error E0137. getMeshes works well.
When i trying to do somethink like
RpMesh* a = header->GetMeshes();
a = newMeshes;
this too not working.
struct RpMeshHeader
{
unsigned int flags;
unsigned short numMeshes;
unsigned short serialNum;
unsigned int totalIndicesInMesh;
unsigned int firstMeshOffset;
RpMesh *getMeshes(void) { return (RpMesh*)(this + 1); }
void setMeshes(RpMesh* newMesh)
{
(RpMesh*)(this + 1)= newMesh;
}
bool isValidMeshId(int meshId)
{
return (meshId != NULL && numMeshes >= meshId);
}
}
Whole file
https://github.com/CrosRoad95/mtasa-blue/blob/f740b0d7410f33ff323cad25bf897725ad44d7d3/Client/sdk/game/RenderWare.h

The error here is quite clear:
void setMeshes(RpMesh* newMesh)
{
(RpMesh*)(this + 1)= newMesh;
}
error: lvalue required as left operand of assignment
the following is not an lvalue and so you cannot assign to it.
(RpMesh*)(this + 1)
The github you linked shows the setMeshes as the following
void setMeshes(RpMesh* newMeshes)
{
RpMesh* meshes = (RpMesh*)(this + 1);
meshes = newMeshes;
}
which is fine in terms of syntax. First you create a pointer meshes to which you assign the address of (this+1) (if this was an array, this+1 would point to the next element in the array) but with a cast!
You cast this hypothetical next element in this array of RpMeashHeader to RpMesh with a C-style cast (which afaik will default to a reinterpret_cast in this case see here for more information)
But has this memory every been allocated? This seems unsafe.

Related

Accessing data from buffer created from boost

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.

Allocating the correct size of struct variable with sub-structs

So I am trying to allocate the correct size for a variable. Then copy another variable to this new one and later access the new variable's data.
Structs:
struct Validations {
int validationId;
int count; // total queries
char queries[];
};
struct Query {
struct Column {
enum Op : int { Equal, NotEqual };
int column;
int value;
Op op;
};
int relationId;
int columnCount; // total columns
Column columns[];
};
Code:
// function that creates the new val
void function1(Validations* val){
int size = sizeof(Validations) + val->count;
Validations *new_val = (Validations*)malloc(size);
memcpy(new_val, val, size);
// I store this val in a global list
}
void function2(){
// I pop the val here
// I am casting here in order to get the values that i want
const char* reader = popped_val->queries;
for (...){
// casting again
const Query* q = (Query*)reader;
// operations....
// SIGSEGV here after reader is incremented and q is casted again
// done with operations, go to next
reader += sizeof(Query)+(sizeof(Query::Column)*q->columnCount);
}
}
The problem is that the new_val size that I am allocating in the first function is probably not the right one because I get a segmentation fault after the second cast of the function2 after trying to access the data.
What I tried:
1) size = 1000; Tried that for testing and it worked so the problem is surely the size.
2) size = sizeof(Validations) + val->count * sizeof(Query) * sizeof(Query::Column) * q->columnCount;. This one looks like the correct one to me but it does not work.
The correct expression should be more like this:
size = val->count * (sizeof(Validations) + sizeof(Query) + (sizeof(Query::Column) * q->columnCount));
But note that you probably have to add up the column counts for each individual Query if they can vary.

How to put integer bits in a float?

I have vertices coming in as float_3's. I want to add an integer to them and then ship them out as float_4's. I don't want to convert the integer into a float with the same value, I need the bits to be exactly the same (the integer is a bucket xyz value bit shifted together).
Here is what I tried:
void tagVerts (vector<float_3> &Verts, vector<float_4> &Output) {
int len = Verts.size();
for (int i = 0; i < len; i++) {
Output[i].xyz = Verts[i];
Output[i].w = reinterpret_cast<float>(XYZTag(Verts[i]));
}
}
it says invalid type conversion :/
EDIT:
float_3 and float_4 are from amp.h, as far as I can tell they are just 3 or 4 floats in a struct with a bunch of conversion and assignment helper functions.
XYZTag is as follows:
int XYZTag(float_3 pos) {
pos = pos * mul + add;
int_3 posi (static_cast<int>(pos.x), static_cast<int>(pos.y), static_cast<int>(pos.z));
return((posi.x << 10) + posi.y << 10) + posi.z;
}
You must not interpret the bits of an int as a float as doing so would violate strict aliasing rules and therefore invoke undefined behavior. The correct way to do this is to copy the bits over using memcpy.
#include <cstring>
inline float
int_bits_to_float(const int bits)
{
static_assert(sizeof(int) >= sizeof(float), "too few bits");
float target;
std::memcpy(&target, &bits, sizeof(float));
return target;
}
As terrible a solution as it might seem to be at a first glance, we should really expect the compiler to figure out that this can be optimized down to a few move instructions. GCC does this even at default optimization level.
You cannot reinterpret_cast<> the int directly. The static_cast<> will not do what you want.
To copy the bit pattern to another type, you need something like:
int val = 23;
float bitCopy = *reinterpret_cast<float*>(&val);
Now, for this to work at all, you better have sizeof(float) and sizeof(int) the same.
Further, we'll have to assume you know what you are doing to want this at all.
reinterpret_cast will not reinterpret an int as a float, but it can reinterpret a pointer.
int temp = XYZTag(Verts[i]);
Output[i].w = *reinterpret_cast<float*>(&temp);
// ^ ^ ^
This will stuff the exact bits of your int into the float Output[i].w. It will be your responsibility to ensure that those types are the same size.

How to get VC++ to access a pointer as a 2D array

I'm doing a little graphics programming and I have a two dimentional array (that varies in size during program execution) that I store using openGL.
So when I go to access it, all I get is a void pointer back.
To make the logic easier, I want the compiler to pretend that it is, and use it as, a 2D array (because arr[i][j] is more concise and less error prone than ptr[i * y + j]).
This clever method of casting I found works fine in GCC (on the linux machines at uni):
Vertex (&vertices)[tess][tess] = *reinterpret_cast<Vertex (*)[tess][tess]>(
glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY)
);
Which basically casts the block of memory pointer openGL gave me to a tess X tess 2D array, and creates a reference of that type to point at it.
This allows me to access the memory like vertices[i][j].
Vertex is just a typedefed struct containing floats
However, at home on my Windows machine, VS'12 has a hissy fit, complaining that it requires the integers where tess is written to be constant (specifically; error C2057: expected constant expression).
I have no idea why.
Now, I understand that VS doesn't support VLA's, but I am not creating an array here, I'm creating a reference to something that I don't know the size of 'till runtime.
So it shouldn't care if the size changes between function calls, right? Why is this not allowed?
Not to be deterred I tried using std::array
std::array<std::array<Vertex, tess>, tess>& vertices;
And apart from the obvious references must be initialized this test didn't help me because it still complained about expression must have a constant value (specifically; error C2975: '_Size' : invalid template argument for 'std::array', expected compile-time constant expression)
I am at a loss at what to try here, I was so proud of the reinterpret_cast and how simple it made things and was sure I wasn't using a method that was contravening the standard.
I don't want to create a std::vector from the pointer then copy the data from that dynamic array back into the pointer location when I'm finished; that just seems so inefficient when the memory block is already just sitting there!
There's no way to create a vector around a pre-existing block of memory, is there? ..no that sounds silly.
I want to see if this can be done without giving up and just using it as Vertex*; Ideas?
Can someone enlighten me as to why it isn't working in VS?
Is there something I can do to get it working (extensions/updates to VS)?
Does VS'13 add support for this?
I am also getting the error C2087: 'vertices' : missing subscript that I can't explain.
As well as these other errors that seem to show VS desperately wants tess to be constant:
error C2466: cannot allocate an array of constant size 0
error C2540: non-constant expression as array bound
error C2440: 'initializing' : cannot convert from 'Vertex [1][1]' to 'Vertex (&)[][1]'
Well that was fun; I implemented a class to handle exactly what I wanted.
It's not as typesafe as I'd like, but I learned a lot doing it
Much like how I felt implementing should-be-a-part-of-the-specification, syntactic-sugar-esque functionality for javascript before I discovered jQuery.
Basically, instead of being able to do this.
int (&array)[x][y] = *reinterpret_cast<int (*)[x][y]>(pointer);
You will have to do this
MDAI<int, 2> array = MDAI<int, 2>(pointer, x, y);
But other than that it works flawlessly! :D
I initially wrote just a specialised TwoDArray class but found I actually had some 3D arrays too.
So instead of implementing a 3D version (that returned TwoDArray when you drilled down) I made something more generic and can help with arrays of as many dimensions as you'd like.
#include <Windows.h>
#include <iostream>
/*MultiDimensional Array Interpretation
has the compiler use a flat pointer reference as if it were a faceted array
C++11/GCC VLA-supporting equivalent:
int (&array)[x][y] = *reinterpret_cast<int (*)[x][y]>(pointer);
using MDAI, <C++11 and MSVS compatible:
MDAI<int, 2> array = MDAI<int, 2>(pointer, x, y);
*/
template<class Type, unsigned int dimension>
class MDAI {
private:
Type* array;
//+1 to guard against zero-length-array
unsigned int bounds[dimension + 1];
public:
//unfortunately I can't use `unsigned int &(dimensions)[dimension]` to make it safe
//because of how operator[]() tries to construct its return value
/*constructor*/
MDAI(Type* array, unsigned int* bounds)
: array(array)
{
std::copy(bounds, bounds + dimension, this->bounds);
}
/*programmer usable constructor for typing of the dimensions, instead of having to declare an array*/
MDAI(Type* array, ...)
: array(array)
{
va_list arguments;
va_start(arguments, array);
for (int index = 0; index < dimension; ++index)
bounds[index] = va_arg(arguments, unsigned int);
va_end(arguments);
}
/*drills down one level into the multi dimensional array*/
MDAI<Type, dimension - 1> operator[](unsigned index) {
if (dimension < 1) {
std::cerr << "MDAI is not an array.\n";
throw 1;
}
if (index < 0 || index >= bounds[0]) {
std::cerr << "Index out of bounds.\n";
throw 1;
}
//figure out how many addresses to jump
for (unsigned int index2 = 1; index2 < dimension; ++index2)
index *= bounds[index2];
return MDAI<Type, dimension - 1>(array + index, bounds + 1);
}
/*'dereferences' the array to get a reference to the stored value*/
Type& operator*() {
if (dimension > 0) {
std::cerr << "MDAI is an array.\n";
throw 1;
}
return *array;
}
/*allows the compiler to automagically 'convert' the MDAI into whatever the user thinks it is*/
operator Type&() {
return **this;
}
/*makes assignment work automagically too!*/
MDAI<Type, dimension>& MDAI<Type, dimension>::operator=(Type value) {
**this = value;
return *this;
}
};
Testing a three-dimensional array of bounds 2-4-3:
void main(unsigned int argC, char** argV) {
using namespace std;
int array[2][4][3] = {
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
{10, 11, 12}
},
{
{13, 14, 15},
{16, 17, 18},
{19, 20, 21},
{22, 23, 24}
}
};
//cast array to pointer, then interpret
MDAI<int, 3> mdai((int*)array, 2, 4, 3);
//testing correct memory access
cout << 15 << ' ' << mdai[1][0][2] << endl;
//testing modifcations using mdai are in array
mdai[0][2][1] = -1;
cout << array[0][2][1] << ' ' << mdai[0][2][1] << endl;
//testing modifications in array show up in mdai
array[1][3][2] = -23;
cout << -23 << ' ' << mdai[1][3][2] << endl;
//testing automatic type casting
cout << -15.0 << ' ' << mdai[0][0][1] * -7.5 << endl;
}
It's as seamless as it would have been had I left it as an array reference.
For compile-time safety I wanted to have redeclare operator*() as, specifically;
Type& MDAI<Type, 0>::operator*()
so you could only call it on a <X, 0>
But I couldn't figure it out.
Similarly get operator[]() to only appear for dimensions greater than 0
Oh well, runtime checking will have to be good enough

Copying arrays via pointers in C++

I've never programmed in C++ before and I'm trying to figure out how to recursively pass segments of an array in a C++ method. I am trying to convert the following pseudo code into C++.
SlowSort(A[1...n])
if n = 2
if A[1] > A[2]
Swap(A[1], A[2])
else if n > 2
SlowSort(A[1...(2n/3)])
SlowSort(A[(n/3+1)... n])
SlowSort(A[1...(2n/3)])
The recursive calls are the bits I'm having a problem with. I was thinking about creating two new arrays that point to the wanted locations but don't know how to go about that, specifically doing that and defining the length of the array. I've tried googling it and searching this site, but there doesn't seem to be anything, that I understand, on it. Also, in case I fudged up somewhere in my code, here's what I have for the first bit.
int SlowSort(int A[])
{
int length = (sizeof(A)/sizeof(*A));
if(length ==2)
{
if(A[0] > A[1])
{
int temp = A[0];
A[0] = A[1];
A[1] = temp;
}
}
In short, how do In covert the else if statement into C++? Explanation would be nice too.
Thanks
You will want to pass indices into the array instead, and use those.
void SlowSort(int A[], int left, int right)
{
if (right - left == 2)
if (A[left] > A[right])
Swap(A[left], A[right]);
else
{
int n = right - left + 1;
SlowSort(A, left, 2 * n / 3);
SlowSort(A, left + n / 3 + 1, right);
SlowSort(A, left, left + 2* n / 3);
}
The above code might not be correct regarding what the algorithm is supposed to do, but you get the idea I'm trying to describe. The thing is: you don't make a copy of the array. Instead, pass the same array always and the range (i.e. the indices) you are sorting.
You simply pass required pointer using the pointer arithmetic. For example the following pseudo code
SlowSort(A[(n/3+1)... n])
could be written as
SlowSort( A + n/3+1, n - n/3 - 1 );
So the function could be declared as
void SlowSort( int A[], size_t n );
As for this code snippet
int SlowSort(int A[])
{
int length = (sizeof(A)/sizeof(*A));
then it is invalid because array is implicitly converted to a ponter to its first element when it is passed as an argument to a function seclared such a way. So the value of length will not be equal to the number of elements.
This is pretty simple. Since arrays are just consecutive pointers. If you have a method:
Your code would look like this:
void slowSort(int[] array, int length)
{
if(length == 2)
{
if(array[0] > array[1])
{
int temp = array[0];
array[0] = array[1];
array[1] = temp;
}
}
else
{
slowSort(&array[0], (2 * length) / 3 - 1);
slowSort(&array[length / 3], length - (length / 3 - 1));
slowSort(&array[0], (2 * length) / 3 - 1);
}
}
The trick I use here is that I pass the pointer of the element I want to start with and the pass the end point.
This works because when you pass an array in C++ you just pass the pointer of the first element. Here I pass a custom pointer of the array.
The modern C++ way to do this would be to pass iterators to the beginning and one-past-the-end of the range. In this case, the iterators are pointers.
void SlowSort(int* begin, int* end)
{
unsigned length = end-begin;
if(length == 2)
{
if(begin[0] > begin[1])
{
std::swap( begin[0], begin[1] );
}
} else if(length>2) {
SlowSort(begin, begin+2*length/3);
SlowSort(begin+length/3, end);
SlowSort(begin, begin+2*length/3);
}
}
then, for the case of working with an entire array:
template<unsigned N>
void SlowSort( int(&Arr)[N] ) {
return SlowSort( Arr, Arr+N );
}
we dispatch it to the iterator version, relying on decaying of array-to-pointer. This has to be a template function, as we want it to work with multiple different array sizes.
Note that an int Arr[] is not an array. It is a different way to say int* Arr, left over as a legacy from C. In fact, as a parameter to a function, saying void foo( int A[27] ) results in void foo( int* A ): function parameters cannot be arrays.
They can, however, be references-to-arrays, which is what the above template function uses.