Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

runtime determine type for C

Tags:

c

runtime-type

If the type of a variable must be determined as runtime in C but the variable name is fixed and given, is there any way to reuse the code that involves the variable?

Actually I am asking about the C counterpart situation of runtime determine type for C++.

If possible please give some examples.

like image 368
Tim Avatar asked Jan 15 '10 09:01

Tim


2 Answers

The C language does not have the object-oriented features that make it meaningful to ask about the run-time type of an object in C++.

You typically implement genericity in C by casting to and from void*. Example: the C function qsort.

If your question is about determining at run-time what actual type a void* pointer points to, that's impossible. The information is simply not stored at all by most compilers.

like image 111
Pascal Cuoq Avatar answered Nov 15 '22 10:11

Pascal Cuoq


One standard technique is to provide a quick type info variable as a parameter and switch on that, and pass all data by reference. inside the function , we recover the value with explicit casting. The void* type is unchecked by the compiler so the danger is sending a type that is unhandled by the function (segmentation fault, data corruption or unknown behavior result). begin by setting up an enumeration of the types you need:

In this case I use the convention TYPE_FUNCTION to represent a function returning a type.

The enum directive chooses successive integers from 0, or you can assign each enumeration its own int value.

typedef enum D_types { 
ANINT, // don't use actual system type names
AFLOAT, 
ADOUBLE, 
ASTRING, 
MY_STRUCT=100, 
MY_STRUCT2=200 
VOID_FUNCTION=1000,   
INT_FUNCTION = 2000,
STRUCT_FUNCTION=3000 
} DATATYPE; 

/*  an f_int is a function pointer to a function */
typedef int (*f_int)(int, void* ); 

In your function definition you send both the data by reference and the type and cast it to the correct type before use:

int myfunction ( DATATYPE dt, void* data,  )
{ 
  int an_int = 0;
  int * ip;  // typed pointers for casting of the void pointer data 
  double * dp;
  char * sp;
  struct My_struct * msp;
  struct My_struct_2 * ms2p;
  f_int  fp;  
  ...

  switch  (dt){
    case ANINT:
       ip = (int*) data; // only pointers can be assigned void pointer values. 
       int i = *ip       // dereference of typed pointer, no dereferencing void pointers.
       ...
       break;
    case ADOUBLE:
       dp = (double*) data;
       double d = *dp;
       ...
       break;
    case ASTRING:
       char * s = strdup( (char*) data);   // cast to char pointer allowed (pointer->pointer)
       ...
       break;
     case MY_STRUCT:
       msp = ( struct My_Struct *) data;  
       char* ms_name = msp->name;   // if my_struct has a name string ...
       float dollarvalue = msp->dvalue; 
       ...
     case INT_FUNCTION:
       fp = (f_int)data;
       an_int = fp( ANINT, 5); 
    }
return an_int;
}

As you might guess, this is playing with matches in a fireworks factory, and not encouraged as a constant practice.

in your code you would call it like this:

double pi =3.14159; 
int g = myfunction( ADOUBLE, &pi  ); // pass by reference, not value   

int j = myfunction (ASTRING , "HEY NOW" );  //C strings pass by ref normally



f_int myfunc = myfunction;   // a function pointer (ref to the functions address )

int r = myfunction ( INT_FUNCTION, myfunc );  /* function as a parameter ... */

Other than for a one-off function it is recommend to use the varargs functions http://www.eskimo.com/~scs/cclass/int/sx11b.html

like image 23
Chris Reid Avatar answered Nov 15 '22 09:11

Chris Reid