-2

I am trying to make 2 variables of structure same across whole array of structures. I am wondering how would you do that as I cant find any clue about what I want to do. I am using C language Here is the structure definition.

struct exp
    {
    uint8_t ReadA[2];
    uint8_t ReadB[2];
    GPIO_TypeDef* port;
    uint16_t pinmask;
    uint8_t Arec[1];
    uint8_t Brec[1];
    } exps[2];
}

I have tried several options.

exps.ReadA={0x41,0x12};
exps[].ReadA[]={0x41,0x12};
exps[].ReadA={0x41,0x12};
exps.ReadA[]={0x41,0x12};
exps->ReadA={0x41,0x12};
exps[]->ReadA[]={0x41,0x12};
exps[]->ReadA[]={0x41,0x12};
exps[]->ReadA[]={0x41,0x12};

None of them work and they give me errors that something is expected before token (],{,;) Only work around I have found to work is to go to write the data snippet by snippet. This is what I mean:

exps[0].ReadA[0]=0x41;
exps[0].ReadA[1]=0x12;

exps[0].ReadB[0]=0x41;
exps[0].ReadB[1]=0x13;

exps[1].ReadB[0]=0x41;
exps[1].ReadB[1]=0x12;

exps[1].ReadB[0]=0x41;
exps[1].ReadB[1]=0x13;

Also I need to make that array of structure bigger (15 to 20 structures)

7
  • just loop over the array and set each member's field individually. Commented Apr 9, 2024 at 10:51
  • I was thinking about that, but I need more variables for the structure. ReadA and ReadB are commands for a IO expander I am useing. I need 15 or more commands per IO expander and that would mean a somewhat complex for loop. Also I dont want to use global variables for that, I am scared of a typo in my code and frying the chips and MCUs flash memory. Commented Apr 9, 2024 at 11:32
  • Well, a loop (or something similar) is what you'll have to do. This magical command does not exist. Commented Apr 9, 2024 at 11:51
  • Are you asking about setting the values at compile-time, or is this operation to be performed (repeatedly) while the program is executing? Commented Apr 9, 2024 at 12:55
  • 1
    please post something one could compile, complete. What about GPIO_TypeDef ? Commented Apr 9, 2024 at 20:21

4 Answers 4

1

Well, just looking at

struct exp
    {
    uint8_t ReadA[2];
    uint8_t ReadB[2];
    GPIO_TypeDef* port;
    uint16_t pinmask;
    uint8_t Arec[1];
    uint8_t Brec[1];
    } exps[2];
}

you see two } and just one { so it is no surprise the compiler does not understand this as valid code. What would be the type of exps[]? Or the members of exp?

If your struct is just what it seems to be, there is a 4-byte header for each one of the structs in the array.

See this example:

#include <stdint.h>
#include <stdio.h>

#define Op4112 0x4112
#define Op4113 0x4113

typedef uint32_t GPIO_TypeDef;  // any

typedef struct
{
    union
    {
        uint8_t  byte[4];
        uint16_t word[2];
        uint32_t dword;
    } Header;
    GPIO_TypeDef* port;
    uint16_t      pinmask;
    uint8_t       Arec[1];
    uint8_t       Brec[1];
} Op;

typedef struct
{
    Op op[20];
} Set;

int dump_value(const Op*, const char*);

int main(void)
{
    uint64_t Iam64 = 0x0102030405060708;
    uint8_t* byte  = (uint8_t*)&Iam64;
    printf("    A 64-bit value: 0x");
    for (size_t i = 0; i < 8; i += 1)
        printf("%02x", (int)byte[i]);
    printf("\n");

    Set my_set;
    my_set.op[0].Header.dword = 0x01020304;
    dump_value(
        &my_set.op[0], "\nUsing 0x01020304 to test    ");
    // set values for op[19] 1st word as 16-bit values
    my_set.op[19].Header.word[0] = Op4112;
    // set values for op[19] 2nd word as 8-bit values
    my_set.op[19].Header.byte[2] = 0x41;
    my_set.op[19].Header.byte[3] = 0x13;
    
    dump_value(
        &my_set.op[19],
        "\nChanging values for header in op[19]    ");
    return 0;
}

int dump_value(const Op* op, const char* msg)
{
    if (msg != NULL) printf("%s", msg);
    printf(
        "Buffer:\n\
       32-bit dword = [ 0x%08x ]\n\
    As 16-bit words = [ 0x%04X, 0x%04X ]\n\
    As 8-bit bytes =  [ 0x%02X, 0x%02X, 0x%02X, 0x%02X ]\n ",
        op->Header.dword, op->Header.word[0],
        op->Header.word[1], op->Header.byte[0],
        op->Header.byte[1], op->Header.byte[2],
        op->Header.byte[3]);
    return 0;
}

output

    A 64-bit value: 0x0807060504030201

Using 0x01020304 to test    Buffer:
       32-bit dword = [ 0x01020304 ]
    As 16-bit words = [ 0x0304, 0x0102 ]
    As 8-bit bytes =  [ 0x04, 0x03, 0x02, 0x01 ]

Changing values for header in op[19]    Buffer:
       32-bit dword = [ 0x41134112 ]
    As 16-bit words = [ 0x4112, 0x4113 ]
    As 8-bit bytes =  [ 0x12, 0x41, 0x13, 0x41 ]

Sure, as told in the comments, you can not assign values to whole arrays at runtime, but we are talking here of a mere 32-bit entity and you can assign values to that, for sure.

See the example above, that uses a union to remap the area as 32, 2x16 or 4x8 bytes, in order to be able to assign values at any internal byte.

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

3 Comments

This isn't equivalent code to what the OP got. You've now built-in an endianness dependency which wasn't there in the original code. And with it the potential for extra bugs as well as non-portability.
Sorry for not answering I had other things to do and started to make an app for the project. The struct extra } at structure declaration was a BIG typo while typing the question. After going several times over my code and reading what I wrote here is better way to tell what I want. I want for structure to have variables (commands) that are same across whole array of structures. In original post you could see how I tried that and it gave me an error. Commands have to be same. Now I am looking into nested structures where inner structure would be command structure.
And later in code I would add variables to that inner structure and than assigne that to whole array of structure. Sorry for the long wait time.
0

OP has revealed, after being asked, that they are searching for a "compile-time" solution.

This stripped down code should point the way.

#include <stdio.h>

int main( void ) {

    struct exp {

        uint8_t A[2];
        uint8_t B[2];
        /* additional struct members are initialised to 0 or NULL */

        } e[ 3 ] = { // NB: 3 specified

            { { 0x41, 0x12 }, { 0x41, 0x13 } }, // <== e[0]
            { { 0x41, 0x12 }, { 0x41, 0x13 } }, // <== e[1]
            /* e[2] initial values default to 0 */

        };

    printf( "e[0] vals: %02X %02X %02X %02X\n", e[0].A[0], e[0].A[1], e[0].B[0], e[0].B[1] );
    printf( "e[1] vals: %02X %02X %02X %02X\n", e[1].A[0], e[1].A[1], e[1].B[0], e[1].B[1] );
    printf( "e[2] vals: %02X %02X %02X %02X\n", e[2].A[0], e[2].A[1], e[2].B[0], e[2].B[1] );

    return 0;
}

Output:

e[0] vals: 41 12 41 13
e[1] vals: 41 12 41 13
e[2] vals: 00 00 00 00

Provide an appropriate value (with appropriate syntax) for every array element and/or struct member to be initialised. Values not provided will be set to 0 (or NULL) by the compiler. There is no appropriate "duplicate these values 'x' times" syntax. (Please don't write nested macros that try to achieve this. Stay away from the forces of darkness.)

1 Comment

thank you for the advice this is working for me.
0

In C, you can't assign whole arrays in run-time. The options are:

  • Initialize the variables to the expected values during the variable definition.
  • memcpy the values into the array member.
  • Assign byte by byte in a loop or similar manual approach.
  • Assign the whole struct object all at once, based on another struct object.

Perhaps a combination of memcpy, a named #define and a "compound literal" (temporary object) would work ok for minimizing code repetition?

#define READ_A_STUFF 0x41,0x12
#define READ_B_STUFF 0x41,0x13

for(size_t i=0; i<n; i++)
{
  memcpy(&exps[i].ReadA, (uint8_t [2]){ READ_A_STUFF }, 2);
  memcpy(&exps[i].ReadB, (uint8_t [2]){ READ_B_STUFF }, 2);
}

Otherwise the "whole struct all at once", also using a compound literal struct, would look like:

for(size_t i=0; i<n; i++)
{
  exps[i] = (struct exp) {
    .ReadA = {0x41, 0x12},
    .ReadB = {0x41, 0x13},
    .port  = ...
    ...
  };
}

2 Comments

But this is just a 32-bit area. You can use an union and assign any values. No repetition, no function call
@arfneto A union fills no obvious purpose here and memcpy is hardly an ordinary function call, if you worry about performance.
0

You can assign whole array only in compile time (during array declaration). But you can't assign the whole array at runtime.

In the following code, assignment to a1 is vaild, but assignment to a2 is invalid.

void main()
{
   /* this is ok. we can assign whole array in compile time. */
   char a1[2] = { 1, 2 };
   char a2[2];
   /* this is error. we can't assign whole array at runtime */
   //a[2] = { 1, 2 };
}

In compile time, you don't even need to define array size. Since it is abvious from the context (char a3[] = { 1, 2 }).

2 Comments

But this is just a 32-bit area. You can use an union and assign any values. No repetition, no function call
I assume a generalized solution. You can use union, for simple cases and assign 4 or 8 int8_t at a time. But keep your code sane.

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.