Prevent array decaying to ** from *[N] - c++

I have declared my array like this:
FT_Interface<4096> *to_make_ft[3] = { /* initialization with existing objects */ };
my interface is declared like this:
template<cyg_ucount32 S, int N>
class FT_Thread {
FT_Thread(FT_Interface<S> *entry[N]){}
};
And i call it (as expected with):
FT_Thread<4096, 3> ft(to_make_ft);
Yet it complains that the pointer has decayed.
ecos/install/include/ft/thread.hxx:70: error: incompatible types in assignment of ‘FT_Interface<4096u>**’ to ‘FT_Interface<4096u>* [3]’
Is there any way to prevent this from happening?

You need
FT_Thread(FT_Interface<S>* (&entry)[N]){}
// note these ^^-----^
With that, you get a reference to the array.
Edit: Of course, if you want a pointer to the array, you can have just that:
FT_Thread(FT_Interface<S>* (*entry)[N]){}
Though you need to call it with FT_Thread<4096,3> ft(&to_make_ft).

I don't know if this is right, but try changing
FT_Thread(FT_Interface<S> *entry[N]){}
to
FT_Thread(FT_Interface<S> (*entry[N])){}
I have a feeling that the compiler thinks that the * refers to the FT_Interface rather than the entry.

Related

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

Structure pointer

I am getting quite confused alot about pointers in structures.
I have a piece of code which i do no understand fully yet,
the code:
typedef struct{
int fildes // basic file descriptor
char* location // location would be somewhere in /dev/tty*
}context0; // structure named 'context' containing the 2 elements above.
context0 someContext; // create a context struct
process(&readLocation); // takes reference from the function 'readlocation'
// i do not know what this process function does.
uint_16_t readLocation(int8_t *buffer, int16_t n, SomeContext){ // buffer pointer, n size read, and fidles
context0 foo = *(context0*) SomeContext; // ???? What Is Going ON right here ????
return read(foo.fd, buffer, n);
}
I have changed some of the names but its the code which i do not fully understand.
Some questions:
since readLocation function is passed as a reference should it not be defined as void* ? infront of the uint_32_t
main question: what does the context0 foo = * (context0*) SomeContext; do?
ok so it seems that (context0 *) is infact a typecast which is done by (int)bar to set some other type to the type of 'int'. this is done to set the variable bar to the type of context.
this typecast can also be done to a pointer type cast wich would be done as (int*) or (struct name*), or in this case (context0 *).
lastly the pointer outside of the parenthisis dereferences the structure pointer to acces whatever it points towards and places this information in the struct context0 foo.
why this is nessesary i do not know but the syntax points to this.
thanks, oh ur welcome np
and thank u Gábor Angyal, but cannot give points or whatever level 1

local array length is different from when it is called from a function

In the following code, std::extent<decltype(columns)>::value calculates the length of the given array. However, when the array is a function argument, the compiler behaves in different way. Could some one help me how to fix it?
output:
local array length: 5
function array length: 0
code:
#include <iostream>
#include <string>
void showcolumns_num(std::string columns[])
{
int columns_num=std::extent<decltype(columns)>::value;
std::cout<<"function array length: "<<columns_num<<std::endl;
}
int main()
{
std::string column_list[]={"col1","col2","col3","col4","col5"};
// local calculation of column number
int columns_num=std::extent<decltype(column_list)>::value;
std::cout<<"local array length: "<<columns_num<<std::endl;
// function calculation of column number
showcolumns_num(column_list);
return 0;
}
You have to pass array by reference to avoid the decay to pointer which so loses size information:
template <std::size_t N>
void showcolumns_num(std::string (&columns)[N])
Live example.
That because of the declaration:
void showcolumns_num(std::string columns[])
is the same as:
void showcolumns_num(std::string * columns)
But declaration:
std::string column_list[]={"col1","col2","col3","col4","col5"};
is the same as:
std::string column_list[5]={"col1","col2","col3","col4","col5"};
So compiler doesn't know about array size inside the function.
Just use the std::vector< std::string >.
The short answer is: Don't use arrays. Instead of string columns[N];, use vector<string> columns; or vector<string> columns(N,"");. In this answer, I'll talk a bit more about arrays, they are "interesting". But arrays are "interesting" in the way that cancer is interesting, somebody has to understand cancer, but we want to get rid of it and most people don't want to be experts.
C arrays are really weird things. They can't be passed by value, but they can be passed by reference, and C++ makes it quite easy. If you are determined - as an intellectual exercise - to pass arrays, then you can use this:
template<size_t N>
void showcolumns_num(std::string (&columns)[N])
Non-array types, like int, or struct Person, or list<vector<string>>, can be passed by value or by reference. But arrays cannot be passed by value.
If you attempt to pass an array by value, the compiler will do a trick where it will instead pass a pointer to the first element of the array. This is called pointer decay.
This means that, without warning, the compiler will rewrite your function declarations
void showcolumns_num(std::string columns[]) { // this is what you write
// changed to
void showcolumns_num(std::string* columns) { // ... but this is what you get
and every call to showcolumns_num will be changed from:
showcolumns_num(column_list); // this is what you write
// changed to
showcolumns_num(&(column_list[0])); // ... but this is what you get
The reason behind this is historical, and is related to an earlier language called B.
Variables are declared as local variables, or as global variables, or as function parameters. For local and global variables, the compiler will generally respect your wishes, but not for function parameters:
void foo(int x[5]) { // silently converted to int *x
int y[10]; // y really will be an array
}

Understanding casting a struct as a void pointer

I found this code in the rendering library for Quake 3. There is this function:
void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap );`
It is being called in a loop somehwere else like this:
R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse );
The weird part is that poly was declared as srfPoly_t *poly. What is going on
here? It is casting a srfPoly_t object to (void *) and then entering the
function as a surfaceType_t object.
Here are the declaration for the relevant structs:
typedef enum {
SF_BAD,
SF_SKIP, // ignore
SF_FACE,
SF_GRID,
SF_TRIANGLES,
SF_POLY,
SF_MD3,
SF_MD4,
SF_FLARE,
SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity
SF_DISPLAY_LIST,
SF_NUM_SURFACE_TYPES,
SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int )
} surfaceType_t;
typedef struct srfPoly_s {
surfaceType_t surfaceType;
qhandle_t hShader;
int fogIndex;
int numVerts;
polyVert_t *verts;
} srfPoly_t;
This is working in C, but I am trying to implement something similar in C++,
but I get the following error:
Error 1 error C2664: 'int RefDef::AddDrawSurf(surfaceType_t *)' : cannot convert argument 1 from 'void *' to 'surfaceType_t *'
It would appear I cannot perform this type of cast in C++, or maybe there is
something else I am unable to understand. I am not very familiar with C++ and
would love to figure out how to set up something similar using it.
I am assuming this has something to do with type checking in C++, so it is not
allowed. How can I implement something similar in C++ in a safe way?
This works in C because structs are simply blocks of memory with each element in the struct laid out consecutively. This cast works because the first n bytes of a srfPoly_t struct consist of the surfaceType_t enum within that struct. The called function tries to interpret the passed-in srfPoly_t as a surfaceType_t, and succeeds because the first n bytes of the argument are, in fact, a surfaceType_t. Do not do this without a very good reason.
Casts from void*'s do not automatically occur in C++ as they do in C. You can use reinterpret_cast to explicitly cast between two different types of structs:
srfPoly_t* mySrfPoly_t;
surfaceType_t* mySurfaceType = reinterpret_cast<surfaceType_t*>(mySrfPoly_t);

C++ Global Array of Queues with variable size

I am working on a project that requires a class QueueArray that is an Array of Queues. It's been a while since I worked with c++ Arrays so I'm having some trouble debugging why my code is throwing errors.
I read Delete an array of queue objects for some inspiration (along with a couple hours on Google), but I am still having errors with the following code:
#include <iostream>
#include <deque>
#include <queue>
using namespace std;
class QueueArray
{
queue<int> theArray[];
QueueArray::QueueArray(int size)
{
queue<int> theArray[] = new queue<int>[size];
//theArray[] = new queue<int>[size]; //this may be closer, but also giving errors
}
};
the errors are:
warning C4200: nonstandard extension used : zero-sized array in struct/union
1> Cannot generate copy-ctor or copy-assignment operator when UDT contains a zero-sized array
and
error C2075: 'theArray' : array initialization needs curly braces
I've read up about the 2nd error, but I can seem to figure out what I need to do to fix it.
I need it to be a variable sized array, with the variable passed to the class, which is why I can not initialize the size of the array up top, and It must be of global scope so I can use it in other functions within the class (the classes can't be passed the array through a parameter).
Later on, the queues will be of a user defined type, but we're letting them be queues of ints right now, not sure if that makes a difference. I keep seeing people suggesting the use of vectors in these cases but I don't have a choice on this one.
Any suggestions would be appreciated.
queue<int>* theArray;
not
queue<int> theArray[];
When allocating an array on the heap you get back a pointer to the start of the array, rather than an array. Thus, you want to declare your array as
queue<int>* theArray;
The use of empty brackets is allowed in some contexts but has specific meaning. It can be used when initializing a statically size array:
queue<int> theArray[] = { queue<int>(), queue<int>() /*...*/ };
creates an array of a size matching the list of initializers and it still can be empty. You can also use empty brackets in the argument list of a function in which case the use is equivalent to using pointer notation, e.g.:
int main(int ac, char* av[])
is identical to
int main(int ac, char** av)
using variable sized arrays is not possible in C++. to make your code working, use a pointer, i.e.
class QueueArray
{
queue<int> * const theArray;
QueueArray::QueueArray(int size)
: theArray (new queue<int>[size])
{ /* ... */ }
~QueueArray()
{ delete[] theArray; }
};
However, in C++ you should really avoid this and use a std::vector instead, i.e.
typedef vector<queue<int>> QueueArray;