Error Performing Pointer Arithmetic on void * in MSVC - c++

Error 1 error C2036: 'const void *' : unknown size file.cpp 111
I don't follow. GCC never complains about void * pointer arithmetic, even on -ansi -pedantic -Wall. What's the problem?
Here's the code-
struct MyStruct {
const void *buf; // Pointer to buffer
const void *bufpos; // Pointer to current position in buffer
};
...
size_t someSize_t, anotherSize_t;
MyStruct *myStruct = (MyStruct *) userdata;
...
if ( (myStruct->bufpos + someSize_t) >
(myStruct->buf + anotherSize_t) ) { // Error on this line
...

You can't do pointer math on a void * pointer. Cast oData->bufpos and oData->anotherConstVoidPtr to something the compiler knows how to deal with. Since you seem to be looking for sizes, which are presumably in bytes, casting to char * should work:
if (((char *)oData->bufpos + someSize_t) ...

On the line:
if ( oData->bufpos ...
The type of bufpos is still void*. The compiler doesn't know what that pointer points to, so it gives you that error.
For pointer arithmetic, void* has no size, so taking an offset, or doing other pointer arithmetic doesn't make sense. Cast it to char* if you want to offset it by a number of bytes:
if(((char*)oData->bufpos) + offset ...
Edited after more code/context was given
If you can help it, try to use char* instead of void*. People in C-land will know what you are talking about, because chars are bytes, and you'll save yourself the headache of casting.

$3.9.1/9-
The void type has an empty set of values. The void type is an incomplete type that cannot be completed. It is used as the return type for functions that do not return a value. Any expression can be explicitly converted to type cv void (5.4). An expression of type void shall be used only as an expression statement (6.2), as an operand of a comma expression (5.18), as a second or third operand of ?: (5.16), as the operand of typeid, or as the expression in a return statement (6.6.3) for a function with the return type void.
I suspect an improper use of 'void' beyond what is allowed by the Standard.

It is really old post but even Visual Studio 2022 supports C11 and c17 MSVC is returning error if you try to add size to void pointer address but for GCC that is totally fine.
void* array_get_ref(const arr_t* this, size_t index)
{
return this->buffer + (index * this->item_size);
}
To solve problem on MSVC you need to cast void pointer to for example char* like this and it will work fine.
void* array_get_ref(const arr_t* this, size_t index)
{
return (char*)this->buffer + (index * this->item_size);
}
If we think it about: any pointer is giving us memory address, so begin of array in this case and we just need to add byte offset , index * item_size which is stored to struct when we created array. (casting does nothing in this case just tricks MSVC compiler)

Related

C++ Cast from ‘std::__tuple... {aka ‘unsigned int*’} to ‘uint32_t’ {aka ‘unsigned int’} loses precision

You may have to forgive me as I'm new to C++ and may have made some fundamental errors with the code I have worked up so far.
static tuple<read_result, uint8_t*> m_scan_record(bool skip, uint32_t& size, FILE* file)
{
read_result result;
tuple<read_result, uint32_t*> rd_rec_size_result = m_read_generic_t<uint32_t>(file);
result = (read_result)get<0>(rd_rec_size_result);
if (result != read_success )
{
return tuple<read_result, uint8_t*>(result, nullptr);
}
size = (uint32_t) get<1>(rd_rec_size_result);
if ( skip )
{
fseek(file, size, SEEK_CUR);
}
// ...
}
template<typename T>
static tuple<read_result, T*> m_read_generic_t(FILE* file)
{
T ret = 0;
read_result result = m_read_from_file_to_buffer(&ret, sizeof(T), file);
if (result == read_success)
{
return tuple<read_result, T*>(result, &ret);
}
return tuple<read_result, T*>(result, nullptr);
}
When I compile this code I am getting this error:
cast from ‘std::__tuple_element_t<1, std::tuple<read_result, unsigned int*> >’ {aka ‘unsigned int*’} to ‘uint32_t’ {aka ‘unsigned int’} loses precision [-fpermissive]
My intentions and what I am expected to do/happen:
In the declaration of m_scan_record, the size argument is declared with a & which is intended to allow me to pass the value by reference, analogous to using the REF c# keyword
I make a call to generic (template) function m_read_generic_t which is called with the specified type <unit32_t> and therefore (according to its definition) will return a type of tuple<read_result, uint32_t*>
Once I have the tuple returned by m_read_generic_t, I want to take the unit32_t value pointed to by the second value of the tuple, and put that value into the size variable mentioned at point 1, above, which presumably will then be accessible to the calling function one step further up the stack.
From the above points you can hopefully see that my intention (and I appreciate that I may be far away in reality!) is that at this line:
size = (uint32_t) get<1>(rd_rec_size_result);
all I am doing is simply grabbing a 'pointed to' value and putting it into a variable of a matching type, much like the oft-cited textbook example:
uint32_t v = 123;
uint32_t* ptr_to_v = &v;
uint32_t x = ptr_to_v; // x == 123
Clearly this is not what is really going on with my code, though, because if it were, I presume that the cast would be un-needed. But if I remove it, like this:
size = get<1>(rd_rec_size_result);
then I get a compile-time error:
a value of type "std::__tuple_element_t<1UL, std::tuple<read_result, uint32_t *>>" cannot be assigned to an entity of type "uint32_t"
I believe therefore that I am doing something badly wrong - but I can't work out what. Is this to do with the way I am taking the pointer out of the tuple; or is there something else going on when it comes to the getting a uint32_t value from a uint32_t* ?
This is all in a C++ environment on Ubuntu 20.04, FWIW
Many thanks in advance for any/all suggestions; please go easy on me!
tuple<read_result, uint32_t*> rd_rec_size_result = ...
The 2nd member of this tuple, as explicitly declared here, is a pointer to a uint32_t. That's what uint32_t * means, in C++.
size = (uint32_t) get<1>(rd_rec_size_result);
This retrieves the uint32_t * and attempts to convert it to a uint32_t. C++ does not work this way. Although this conversion can be forced your compiler has every right to believe that whatever this code is trying to do it must be wrong.
Perhaps I was wondering initially, your intention was to dereference the pointer. This is the reason for your compilation error, in any case. If your intention was to, truly, dereference this pointer, then this would've been a simple matter of changing this to
size = *get<1>(rd_rec_size_result);
However, that's not going to be the end of your troubles. Even after this compilation error is fixed, this way, the shown code will still be badly, badly broken.
This is because m_read_generic_t returns a pointer to a local object, which will get destroyed when the function returns, and attempting to dereference this pointer, here, will make demons fly out of your nose.
The real fix here is to change m_read_generic_t to not return a pointer as the 2nd value in the tuple in the first place, thus eliminating the compilation error in the first place.

Explaining sizeof(((rs_comm*)0)->ab[0]);

At xdn-project/digitalnote ./src/crypto/crypto.cpp file there is an error at line 338 when compiling (using cmake):
return sizeof(rs_comm) + pubs_count * sizeof(rs_comm().ab[0]);
^
error: value-initialization of incomplete type
‘Crypto::rs_comm:: []’
I found the solution on cryptonotefoundation/cryptonote:
return sizeof(rs_comm) + pubs_count * sizeof(((rs_comm*)0)->ab[0]);
I can play with Java JDK quite well, but currently at C++ need help :) It would be nice to see detail explanation of this code part:
sizeof(((rs_comm*)0)->ab[0]);
My questions are:
Asterisk after rs_comm - what its for?
0) - what is the purpose of 0 here?
The fragment of code:
struct rs_comm {
Hash h;
struct {
EllipticCurvePoint a, b;
} ab[];
};
static inline size_t rs_comm_size(size_t pubs_count) {
return sizeof(rs_comm) + pubs_count * sizeof(rs_comm().ab[0]);
}
sizeof is an operator that return the size of a specific type. It can work directly with a type or with an expression.
This part (rs_comm*)0 is taking 0 (0 is a valid null pointer constant) and casting it to a pointer of the struct rs_comm (or the class, I don't know the definition of rs_comm, but I am guessing).
Now, it is accessing using the -> operator to the data-member ab. ab has to be define as array, so it can get the first item in the array.
Because, sizeof doesn't really evaluate the expression but just figuring out the type and get the size of it.
So, the final result is the size of the first element in the array ab for the class/struct rs_comm.
So ab is an member of struct rs_comm, and is an array.
If you have a rs_comm object, i.e. rs_comm rs;, but you don't know the type of ab, you want to know its size, sizeof(rs.ab[0]) will do.
If you have a pointer to rs_comm, i.e. rs_comm *p_rs;, then sizeof(p_rs->ab[0]) will do the same thing.
If you don't have a rs_comm object nor a pointer to rs_comm, you can change a NULL pointer to a pointer to rs_comm, this is what ((rs_comm *)0) do.
Replace the p_rs in sizeof(p_rs->ab[0]) with ((rs_comm *)0), you get sizeof(((rs_comm *)0)->ab[0]).
sizeof(variable) .
return the size variable data type .
like
char x ;
cout << sizeof(x) ;
the result would be

typecast struct pointer into char pointer reference

Is it possible to typecast struct pointer into char pointer reference? I know that we can cast any pointer type to any other pointer type. But I got an error when I tried to typecast structure. I am using C++ compiler.
Error :
error: invalid initialization of non-const reference of type 'char*&' from a temporary of type 'char*'
Please see below example:
struct test {
int a;
bool y;
char buf[0];
}
struct test *x_p = NULL;
char *p = "Some random data......"; // this can be more than 64 bytes
x_p = (struct test *) malloc(sizeof(struct test) + 65);
x_p->a = 10;
x_p->y = false;
memcpy(x_p->buf, p, 64); //copy first 64 bytes
/* Here I am getting an error :
* error: invalid initialization of non-const reference of type 'char*&' from a temporary of type 'char*'
*/
call_test_fun((char *)x_p);
// Function Declaration
err_t call_test_fun(char *& data);
The function declaration should be:
err_t call_test_fun(char * data);
you had an erroneous & . The function definition should match.
Note that your code uses techniques that are not part of Standard C++: having a zero-sized array in a struct, and writing directly into malloc'd space. Maybe you are using a compiler with those things as extensions but it will be frowned on by many people as being prone to error. There is undoubtedly a better way to do whatever it is you are trying to do.

Can I assign void* pointer to char* pointer?

I am coding for re-implementing malloc function. I saw a man's example code , which has some strange code like this
struct s_block{
size_t size; // size per block
int free; // whether free flag exist
t_block pre;
t_block next;
void *magic_ptr;
int padding; // bytes for padding
char data[1]; // first byte of data, i.e. the address returned from malloc
};
typedef struct s_block *t_block;
t_block get_block(void *p) {
char *tmp;
tmp = p;
...
}
but I use gcc or g++ to compile this code, the error is "can't use void* pointer to char* pointer".
I want to know where the question arise? gcc or g++ ? code is error?
In C++ you must explicitly cast a void* to another type:
char *tmp = static_cast<char*>(p);
In C this isn't the case and you can assign a void* to any pointer type without casting.
You have to use explicit cast to cast void* to any other pointer whereas other way is implicit.
char* temp = static_cast<char*> (p);
One thing to note here is your initial pointer ( which currently is represented by void* ) should be of type char* to avoid any issues.
That is valid C code, the error you're getting is from the (more strict) C++ standard. If you want to compile that in C++, simply cast the pointer to char * explicitly.

static_cast void* char* vs static_cast void** char**

If I do the following all is ok:
char* cp = "abc";
void* vp = NULL;
vp = static_cast<void*>(cp);//ok
cp = static_cast<char*>(vp);//ok
But the following is not:
char** cpp = &cp;
void** vpp = NULL;
vpp = static_cast<void**>(cpp);//error C2440: 'static_cast':
//cannot convert from 'char **' to 'void **'
cpp = static_cast<char**>(vpp);//error C2440: 'static_cast':
//cannot convert from 'void **' to 'char **'
Please can someone explain to me why the second examples are not allowed. Please don't quote the C++ standard as your whole answer, because I've already seen answers that quote it, and I don't understand what they meant. I want to understand why the second examples don't work (ie. if you could give an example where it would be dangerous that would be a great help). Because I don't get it. To me, both examples are casting pointers. Why does an additional level of indirection make any difference?
A void * pointer can point at "anything", and it is valid to convert all pointers to a void *, and it is valid to convert all pointers from void * to some other type.
However, a void ** is a pointer that points to a void * value. And a char ** is a pointer that points to char * value. These types don't point to the types that are convertible from one another. You can, if you NEED to do this, use void **vpp = reinterpret_cast<void **>(cpp);, but it's "not safe" (you are basically telling the compiler "Look, I know what I'm doing here, so just do it", which may not do what you actually expected...)
The restriction is to avoid breaking the type system. The first conversion is fine:
type *p = ...;
void *vp = p;
While you are giving away the type, you cannot inflict too much damage to the original value without since there is little to be done with a void object and all changes to vp are local to the pointer and cannot affect p.
If the second case was allowed:
type **p = ...;
void **vp = p;
Then perfectly looking and correct code could break your application. For example:
int *parray[10];
int **p = parray;
void **vp = p;
*vp = new double(); // now parray[0] is a pointer to a double object,
// not a pointer to an int!!!
The type system has been subverted.
That is, the problem is that in the second case there are operations that can be applied to the destination pointer that can modify the original object and cause bugs. Similar examples can be found with const other cases (you can convert int* to const int*, but you cannot convert int** to const int**...).