Sevenless
Sevenless

Reputation: 2855

Arrays in structures

I'm new to C and having a problem with array types when embedded in structures. The following is an example of my issue:

typedef struct {
    double J[151][151];
} *UserData;

static int PSolve(void *user_data, N_Vector solution)
{
UserData data;
data = (UserData) user_data;

double J[151][151];
J = data->J;

/* Solve a matrix equation that uses J, stored in 'solution' */

return(0);
}

When I try to compile this I get error: incompatible types when assigning to type ‘double[151][151]’ from type ‘double (*)[151]’

My current workaround for this has been to replace 'J[x][y]' by 'data->J[x][y]' in the code to solve the matrix equation, but profiling has shown this to be less efficient.

Changing the arguments to PSolve is not an option because I'm using the sundials-cvode solver which prescribes the type and order of the arguments.

Upvotes: 1

Views: 788

Answers (4)

Jens Gustedt
Jens Gustedt

Reputation: 78973

You can't assign to an array. You should look up about the difference between arrays and pointers in C.

What you need in your code is just something like this:

double (*J)[151] = data->J;

that is a pointer to arrays of length 151. Or if you'd like with typedefs

typedef double line[151];
line *J = data->J;

that's all, you should not copy the data but just the pointer to the data.

Edit: But seeing the whole thread of answers, I think all of that is pure speculation where your bottleneck might be. It could just be anywhere, e.g that you are accessing the matrix the "wrong way round", column wise, or whatever. Or that pumping the data from memory is just dominating your computation.

Perhaps consider to look into the assembler that your compiler produces (option -S) to see if there is something fishy.

Upvotes: 0

caf
caf

Reputation: 239321

The root cause of your issue is that array types cannot be directly assigned in C. You must explicitly use memcpy(), as karlphillip's answer shows.

Note however that performing the copy may wipe out the optimisation gains you make in the remainder of the function. Presumably, the solution argument is a pointer, and the optimiser is worried about potential aliasing between user_data / data and solution. As an alternative, if you have a compiler that supports C99's restrict keyword, is to use that qualifier on the arguments:

static int PSolve(void * restrict user_data, N_Vector restrict solution)

This promises the compiler that those pointers do not alias, and should allow you to directly use data->J without sacrificing the compiler optimisations.

Some compilers make the restrict keyword available in C89 mode under a spelling such as __restrict - consult your compiler documentation for more details.

Upvotes: 2

karlphillip
karlphillip

Reputation: 93468

typedef struct {
    double J[151][151];
} UserData; // This is a new data structure and should not a pointer!

static int PSolve(void *user_data, N_Vector solution)
{
UserData* data; // This should be a pointer instead!
data = (UserData*) user_data;

double J[151][151];
memcpy(J, data->J, sizeof(double) * 151 * 151); // use memcpy() to copy the contents from one array to another

/* Solve a matrix equation that uses J, stored in 'solution' */

return(0);
}

Upvotes: 5

Tiago
Tiago

Reputation: 1337

Try defining local variable double J[151][151] as double **J.

Upvotes: -1

Related Questions