0

I have two structs in a library I cannot change. p.e:

struct{
    uint8_t test;
    uint8_t data[8];
}typedef aStruct;

struct{
    uint8_t value;
    uint8_t unimportant_stuff;
    char data[8];
}typedef bStruct;

aStruct a;
bStruct b;

In my application there is a process that permantently refreshs my aStruct's. Now I have a buffer of bStruct's I want to keep updated as well. The data[] array is the important field. I don't really care about the other values of the structs.

I already made sure, that on that specific system where the code runs on, a "char" is 8Bits as well.

Now I'd like to make the "b.data" array point to exactly the same values as my "a.data" array. So if the process refreshs my aStruct, the values in my bStruct are up to date as well.

Therefore that in C an array is only a pointer to the first element, I thought something like this must be possible:

b.data = a.data

But unfortunately this gives me the compiler-error:

error: assignment to expression with array type

Is there a way to do what I intend to do?

Thanks in advance

9
  • Thats not how this works. Assign a.data[0] = (char) b.data[0] and so forth. Use a for loop if you like. Commented Nov 6, 2015 at 7:03
  • In the bStruct, you would need to change char data[8] to char *data, so the answer is no. Commented Nov 6, 2015 at 7:04
  • Arrays don't "point" to data. And are not assignable. Look up how to copy arrays, there should be many duplicates. Commented Nov 6, 2015 at 7:04
  • 1
    As I said, the answer to your question is NO. Commented Nov 6, 2015 at 7:07
  • 2
    @TomMekken As I said, arrays don't point. Commented Nov 6, 2015 at 7:07

3 Answers 3

1

Okay, according to the input I got from you guys, I think it might be the best thing to redesign my application.

So instead of a buffer of bStruct's I might use a buffer of aStruct*. This makes sure my buffer is always up to date. And then if I need to do something with an element of the buffer, I will write a short getter-function which copies the data from that aStruct* into a temporary bStruct and returns it.

Thanks for your responses and comments.

Sign up to request clarification or add additional context in comments.

Comments

0

If you want b.data[] array to point to exactly the same values, then you can make data of b a char* and make it point to a's data.

Something like

struct{
uint8_t value;
uint8_t unimportant_stuff;
char* data;
}typedef bStruct;

and

b.data = a.data;

But, keep in mind, this means that b.data is pointing at the same memory location as a.data and hence, changing values of b.data would change values of a.data also.


There is another way of doing this. It is by copying all the values of a.data into b.data. Then, b.data would merely contain the same values as a.data, but it would point to different memory locations.

This can either be done by copying one by one. In a for loop for all the 8 elements.

Or, to use memcpy()


NOTE

Arrays cannot be made to point to another memory locations. As they are non modifiable l-value. If you cannot modify the structs, then you have to use the second method.

4 Comments

this is exactly what I want to do ... the problem is, that I cannot change the structs (both defined in a library)
@TomMekken, Then you will have to go with the second method. Because arrays cannot be made to point to some other memory location. They are non-modifiable l-value
yeah, but I'm not notified about the update. So I don't know when to copy the values ... therefore I wanted the pointer. Okay, so it seems there is no way to do that without a "real" pointer.
@TomMekken, what you can do is keep a thread to detect changes in a.data values. It would trigger the copy only when a change to a.data values is detected. When a change is detected, the new values will then be copied to b.data
0

What you are asking is not possible when you can not modify the existing struct definitions. But you can still automate the functionality with a bit of OO style programming on your side. All of the following assumes that the data fields in the structs are of same length and contain elements of same size, as in your example.

Basically, you wrap the existing structs with your own container. You can put this in a header file:

/* Forward declaration of the wrapper type */
typedef struct s_wrapperStruct wrapperStruct;
/* Function pointer type for an updater function */
typedef void (*STRUCT_UPDATE_FPTR)(wrapperStruct* w, aStruct* src);
/* Definition of the wrapper type */
struct s_wrapperStruct
{
    STRUCT_UPDATE_FPTR update;
    aStruct* ap;
    bStruct* bp;
};

Then you can can create a factory style module that you use to create your synced struct pairs and avoid exposing your synchronization logic to uninterested parties. Implement a couple of simple functions.

/* The updater function */
static void updateStructs(wrapperStruct* w, aStruct* src)
{
    if ( (w != NULL) && (src != NULL) )
    {
        /* Copy the source data to your aStruct (or just the data field) */
        memcpy(w->ap, src, sizeof(aStruct));
        /* Sync a's data field to b */
        sync(w); /* Keep this as a separate function so you can make it optional */
    }
}

/* Sync the data fields of the two separate structs */
static void sync(wrapperStruct* w)
{
    if (w != NULL)
    {
        memcpy(w->bp->data, w->ap->data, sizeof(w->bp->data));
    }
}

Then in your factory function you can create the wrapped pairs.

/* Create a wrapper */
wrapperStruct syncedPair = { &updateStructs, &someA, &someB };

You can then pass the pair where you need it, e.g. the process that is updating your aStruct, and use it like this:

/* Pass new data to the synced pair */
syncedPair.update( &syncedPair, &newDataSource );

Because C is not designed as an OO language, it does not have a this pointer and you need to pass around the explicit wrapper pointer. Essentially this is what happens behind the scenes in C++ where the compiler saves you the extra trouble.

If you need to sync a single aStruct to multiple bStructs, it should be quite simple to change the bp pointer to a pointer-to-array and modify the rest accordingly.

This might look like an overly complicated solution, but when you implement the logic once, it will likely save you from some manual labor in maintenance.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.