0

I need to do some assigns as follows.

In struct REGS, tiles are arranged by names;

while on outside, tiles are arranged by indices.

#include <stdio.h>

typedef struct TILE {} TILE;

typedef struct REGS {
    TILE tile00, tile01, tile02,
         tile10, tile11, tile12,
         tile20, tile21, tile22;
} REGS;

int main() {
    TILE tiles[3][3];
    REGS regs;

    regs.tile00 = tiles[0][0];
    regs.tile01 = tiles[0][1];
    regs.tile02 = tiles[0][2];
    regs.tile10 = tiles[1][0];
    regs.tile11 = tiles[1][1];
    regs.tile12 = tiles[1][2];
    regs.tile20 = tiles[2][0];
    regs.tile21 = tiles[2][1];
    regs.tile22 = tiles[2][2];

    return 0;
}

so I suppose I need a loop like:

for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 3; ++j) {
        // not real code
        regs.tile##i##j = tiles[i][j];
    }
}

for doing that, I defined some macros:

#define TILE_MEM(prefix, i, j) prefix##i##j

#define WRITE_TILE(base, mem, value) (base.mem = value;)

#define MACRO_LOOP(i,j) (WRITE_TILE(regs, TILE_MEM(tile, i, j), tiles[i][j]))

then I did this:

for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 3; ++j) {
        MACRO_LOOP(i, j);
    }
}

but it doesn't compile.

PLEASE HELP!

5
  • 1
    The C preprocessor does not work like that. Your MACRO_LOOP will only be replaced once at compile time. You migh try to put REGS regs into a union that holds an array besides REGS content. Commented Jan 11, 2023 at 6:31
  • 2
    Why doesn't the REGS struct simply contain an array? Commented Jan 11, 2023 at 7:05
  • @Chris because they are hardware registers, they are different register with different names... Commented Jan 11, 2023 at 7:08
  • 1
    Names are irrelevant. Are they in sequence, no gaps, same size? Do I understand correctly that we are talking memory-mapped registers? I am used to that in embedded environments. Please provide some examples of how they are accessed; because the shown code does not access hardware. Commented Jan 11, 2023 at 8:24
  • What's typedef struct TILE {} TILE; supposed to be? That's invalid C and doesn't make any sense. Commented Jan 11, 2023 at 10:39

1 Answer 1

2

Macros are the wrong solution and they only exist at compile-time, so you can't use them together with run-time values.

The standard way of creating a type where you can either access items by individual names or as an array, is to use a union:

typedef union {
  struct  // anonymous struct, must be compiled with a standard C compiler
  {
    TILE tile00, tile01, tile02,
         tile10, tile11, tile12,
         tile20, tile21, tile22;
  };
  TILE tile [3][3];
} REGS;

Now you can either use individual names:

regs.tile00 = tiles[0][0];
regs.tile01 = tiles[0][1];

Or the array type:

for(size_t i=0; i<3; i++)
{
  for(size_t j=0; j<3; j++)
  {
    regs.tile[i][j] = tiles[i][j];
  }
}

(Do keep struct alignment/padding in mind however, since there's some special cases where that might trip union type punning over.)

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

1 Comment

And just for completeness, the SEVERELY NOT RECOMMENDED version that does use macros: godbolt.org/z/rP5jf7W99. And this relies on a list on constants getting hardcoded.

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.