1

I want to use a dynamic variable whose value will vary during the run time.

eg

char * aVar = "ABC";
char * bVar = "DEF";
char * cVar = "XYZ";

char *dVar = NULL;

dVar = foo1();

print dVar;

foo1 internally calls foo2, which should return the variable names (like "aVar", "bVar" or "cVar"). foo1 should return the value of said variable as named according to foo2's return value.

to get the variable name we can use (non-standard) macro:

##define GET_VAR(varname) #varname; 

... but how am I able get the value of the variable named?

obataku
  • 29,212
  • 3
  • 44
  • 57
puneet
  • 79
  • 1
  • 7
  • 5
    Now why on earth would you be doing that in C? – obataku Sep 15 '12 at 07:48
  • @oldrinb - I was going to say something along that line of thought. Why not just return the appropriate pointer (Even though having global variables is a bad idea) – Ed Heal Sep 15 '12 at 07:54
  • Or pass an out param to functions foo1() and foo2() respectively which simply put the value in the param after completing processing – fkl Sep 15 '12 at 07:59
  • 1
    @oldrinb: personally I don't seem to find myself doing it even in languages that support it. The languages that allow it mostly seem to have easy-to-use associative containers. Not by coincidence ;-) – Steve Jessop Sep 15 '12 at 08:26

4 Answers4

4

The simple answer here is that this is not possible in C.

The longer answer is that this requires introspection and dynamic features in a language, which is something that is generally only seen in scripting languages such as Python. And even there doing something like this is not encouraged.

I suggest that you reconsider the problem you are trying to solve and check if there might not be a better method to approach it. Perhaps using an array, map or hash table might be an alternative approach that works for you.

Wichert Akkerman
  • 4,918
  • 2
  • 23
  • 30
  • Although it's not advisable, you can do dynamic loading - see my answer. –  Sep 15 '12 at 07:55
  • That's certainly an interesting approach. I doubt it is very portable though, and it might break if a compiler or linker does some unexpected optimisation. Still - bonuspoints for coming up with this :) – Wichert Akkerman Sep 15 '12 at 07:59
  • it should be portable across POSICes. –  Sep 15 '12 at 08:04
2

C is not a dynamic language - you can't really do this. You'd just better use some kind of data structure, such as a dictionary (key-value store, associative array, however you call it) for this purpose.

Well, unless... unless you have a POSIX-conformant system and you like evil dynamic loading.

#include <dlfcn.h>
#include <stdio.h>

int globalVarOne = 1;
int globalVarTwo = 2;
int globalVarThree = 3;

int getValueOfVariableNamed(const char *name)
{
    void *ptr = dlsym(RTLD_SELF, name);
    return *(int *)ptr;
}

int main()
{
    printf("globalVarOne = %d\n", getValueOfVariableNamed("globalVarOne"));
    // etc.
}

Prints:

globalVarOne = 1

Note that this only works for global variables.

Edit: as @oldrinb pointed out, you can also do this on Windows if you substitute void *ptr = GetProcAddress(GetModuleHandle(NULL), name); instead of void *ptr = dlsym(RTLD_SELF, name);.

1

You can't do it directly in C.

You can do something like this however:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct Binding
{
  int* pIntVar;
  const char* IntVarName;
  struct Binding* pNext;
} Binding;

Binding* Bindings = NULL;

void BindVar(const char* IntVarName, int* pIntVar)
{
  Binding* b;
  if ((b = malloc(sizeof(Binding))) != NULL)
  {
    b->IntVarName = IntVarName;
    b->pIntVar = pIntVar;
    b->pNext = NULL;
    if (Bindings == NULL)
    {
      Bindings = b;
    }
    else
    {
      Binding* bs = Bindings;
      while (bs->pNext != NULL)
      {
        bs = bs->pNext;
      }
      bs->pNext = b;
    }
  }
  else
  {
    fprintf(stderr, "malloc() failed\n");
    exit(-1);
  }
}

int* GetVarPtr(const char* IntVarName)
{
  Binding* bs = Bindings;
  while (bs != NULL)
  {
    if (!strcmp(bs->IntVarName, IntVarName))
    {
      return bs->pIntVar;
    }
    bs = bs->pNext;
  }
  fprintf(stderr, "variable \"%s\" not bound yet!\n", IntVarName);
  exit(-1);
}

int main(void)
{
  int ABC = 111, DEF = 222, XYZ = 333;
  const char* varName = NULL;

  BindVar("ABC", &ABC);
  BindVar("DEF", &DEF);
  BindVar("XYZ", &XYZ);

  printf("variable \"%s\" = %d\n", "ABC", *GetVarPtr("ABC"));
  printf("variable \"%s\" = %d\n", "DEF", *GetVarPtr("DEF"));
  printf("variable \"%s\" = %d\n", "XYZ", *GetVarPtr("XYZ"));

  // Pick a variable randomly by name

  switch (rand() % 3)
  {
  case 0: varName = "ABC"; break;
  case 1: varName = "DEF"; break;
  case 2: varName = "XYZ"; break;
  }

  printf("variable \"%s\" (selected randomly) = %d\n", varName, *GetVarPtr(varName));

  return 0;
}

Output (ideone):

variable "ABC" = 111
variable "DEF" = 222
variable "XYZ" = 333
variable "DEF" (selected randomly) = 222

Since GetVarPtr() returns a pointer to a variable, you can not only get the variable's value, but also set it.

You can even hide the pointer thing behind a macro:

#define VARIABLE(NAME) (*GetVarPtr(NAME))

In this way you can do things like this (ideone):

VARIABLE("ABC") = 1;
VARIABLE("DEF") = 2;
VARIABLE("XYZ") = 3;

printf("variable \"%s\" = %d\n", "ABC", VARIABLE("ABC"));
printf("variable \"%s\" = %d\n", "DEF", VARIABLE("DEF"));
printf("variable \"%s\" = %d\n", "XYZ", VARIABLE("XYZ"));
Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
0

You can't use macros during runtime.

You should use an array.

micnyk
  • 726
  • 8
  • 27