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;
}
I defined two arrays of different sizes to try and make something more generic.
We define a structured called
array_t
which holds information about our arrays.We initialize our structure with the arrays. This is the first bit of preprocessing ugliness.
__set(v)
depends onstatic
arrays to function (ie. it won't work withmalloc
arrays).# v
converts the name of the variable to a string.The next interesting bit is
sizeof(v) / sizeof(v[0])
which calculates them
dimention of the array by dividing the total size of the array by the row size.sizeof(v[0]) / sizeof(v[0][0])
divides the total row size by the size of the type.getarray
is where the lookup happens. You can get a name and an index, thensnprintf
will create a string for you and loop up in our global tablearray
.val
is a wrapper to give you the element at a given index of a 2D array.print_array
... well, prints the array.