Home > front end >  C: Concatenate a word and a number to single identifier runtime
C: Concatenate a word and a number to single identifier runtime

Time:09-22

I want to concatenate one word and one number to a single identifier like using the ## preprocessor operator, and use this to index an array. However, it has to happen at runtime. Ideally, something like this:

#include <stdio.h>

#define RUNTIME_CONCAT(a,b) //Insert concatenating operation here

int main(){
    int foo1[2][1] = {{2}, {5}};
    int foo2[2][1] = {{6}, {9}};

    /*
    By some means acquire number a here
    */

    int* print_val = RUNTIME_CONCAT(foo, a)[1];

    printf("Value: %d\n", *print_val);
    return 0;
}

Is this possible?

CodePudding user response:

If yu want to use macro:

typedef int (*arr21)[2][1];

#define RT(arr, x)  (int *)(((arr21 []){&arr ## 1, &arr ## 2})[x])

typedef is only for the sake of simplicity - otherwise the syntax of compound literal would be quite hard to read.

#define RT(arr, x)  (int *)(((arr21 []){&arr ## 1, &arr ## 2})[x])

int main(void){
    int foo1[2][1] = {{2}, {5}};
    int foo2[2][1] = {{6}, {9}};

    volatile int a = 1;

    int* print_val = RT(foo, a);
    printf("Value: %d\n", *print_val);

    return 0;
}

https://godbolt.org/z/rjWMrzda9

CodePudding user response:

I propose a little bit of ugly code, but I think it is what you're looking for. Comments after the code.

/* so.c
 */
#include <stdio.h>
#include <string.h>

int foo1[2][1] = {{2}, {5}};
int foo2[2][3] = {{6, 3, 1}, {9, 7, 5}};

struct array_t {
    char *name;
    void *ptr;

    /* int foo[m][n] */
    size_t m, n;
};

struct array_t array[] = {
#define __set(v)    {# v, v, \
    sizeof(v) / sizeof(v[0]), \
    sizeof(v[0]) / sizeof(v[0][0])}
    __set(foo1),
    __set(foo2),
#undef __set
};

void *getarray(char *base, int idx)
{
    char name[100];
    snprintf(name, 100, "%s%d", base, idx);

    for(int i = 0; i < sizeof(array)/sizeof(struct array_t); i  )
        if(!strcmp(array[i].name, name))
            return &array[i];
    return NULL;
}

int val(struct array_t *array, int m, int n)
{
    int *p = array->ptr;
    return p[m * array->n   n];
}

void print_array(struct array_t *array)
{
    printf("Array: %s[%zu][%zu]\n\n", array->name, array->m, array->n);

    for(int m = 0; m < array->m; m  )
        for(int n = 0; n < array->n; n  )
            printf("%s[%d][%d] = %d\n",
                array->name, m, n, val(array, m, n));

    printf("\n\n");
}

int main(void)
{
    struct array_t *p1, *p2;

    p1 = getarray("foo", 1);
    p2 = getarray("foo", 2);

    print_array(p1);
    print_array(p2);

    printf("foo2[1][2]: %d\n", val(p2, 1, 2));
    return 0;
}
  1. I defined two arrays of different sizes to try and make something more generic.

  2. We define a structured called array_t which holds information about our arrays.

  3. We initialize our structure with the arrays. This is the first bit of preprocessing ugliness.

  4. __set(v) depends on static arrays to function (ie. it won't work with malloc arrays). # v converts the name of the variable to a string.

  5. The next interesting bit is sizeof(v) / sizeof(v[0]) which calculates the m dimention of the array by dividing the total size of the array by the row size.

  6. sizeof(v[0]) / sizeof(v[0][0]) divides the total row size by the size of the type.

  7. getarray is where the lookup happens. You can get a name and an index, then snprintf will create a string for you and loop up in our global table array.

  8. val is a wrapper to give you the element at a given index of a 2D array.

  9. print_array... well, prints the array.

  • Related