¿Cómo pasar un operador matemático C (+ – * /%) a un resultado de función = mathfunc (x, +, y)?

Estoy escribiendo algunas rutinas matemáticas en un progtwig de C para enteros de precisión múltiple y quiero poder escribir expresiones fácilmente, pero manejar las matemáticas con mi propia función. Así que quiero una manera que me permita hacer esto:

MPI x=mpi(5),y=mpi(6),z; z=mpimath(x,+,y); 

¿Es esto posible en C codificando el carácter de alguna manera? Sé que no hay sobrecarga del operador, por lo que tiene que ser una llamada de función, y el signo + no puede ser parte del nombre de la función.

Sí, es posible.

Puede interactuar con su función utilizando una macro. Una macro te da poderes adicionales sobre la apariencia física del código. En particular, puede estrechar un argumento. Y puede pasar cualquier token C completo como un argumento a una macro.

Así que haz algo como esto:

 #define mpimath(X,F,Y) (mpimath)(X,#F,Y) /* stringify F */ 

Luego define tu función para aceptar un parámetro char * . Esto dará como resultado la cadena "+" para el argumento + . Al usar el mismo nombre para la macro, las llamadas a la función son interceptadas por esta macro, por lo que una llamada como esta:

 mpimath(p,*,r) /* macro invocation */ 

se expande a

 (mpimath)(p,"*",r) /* function call */ 

. Los parámetros alrededor del nombre de la función no son estrictamente necesarios aquí, ya que una macro no puede ser recursiva, se expandirá a la cosa correcta. Pero envolver parens también es la forma de llamar explícitamente a la función sin pasar por las definiciones de macros, por lo que encuentro que ayuda a auto-documentar el código para agregarlos aquí.

Puedes usar algo como char *ops="+-*/"; int op=strstr(ops, f)-ops; char *ops="+-*/"; int op=strstr(ops, f)-ops; para asignar la cadena a un entero pequeño (*) que luego se puede usar para indexar una tabla de función. O puede desreferenciar la cadena para obtener un char que puede usar en un switch .

 MPI mpimath(MPI x, char *f, MPI y){ switch(*f){ case '+': //... break; case '-': //... break; //etc. } 

O puede mover la desreferenciación de nuevo a la macro. Se ve un poco raro en la macro. Pero creo que hace que la función se vea mejor.

 #define mpimath(X,F,Y) (mpimath)(X,*#F,Y) /* stringify and deref F */ MPI mpimath(MPI x, char f, MPI y){ switch(f){ case '+': //etc. } } 

Edición: algunos detalles sobre el código real que dio origen a este par q / a de intercambio de conocimientos .

La motivación para pasar al operador como un char surgió indirectamente, pero nunca en la forma simplificada que se muestra en la pregunta. El uso actual de la macro se ve así para la función + :

  BIN_MATH_FUNC(+,AV(z)[i],AV(a)[i],AV(w)[i],plusover,plusdomainI,plusdomainD) 

y la macro también maneja directamente tipos nativos como int y double . Así que el marco que la función mpi necesitaba para adaptarse ya estaba configurado para distinguir las operaciones por su operador C real (como un argumento macro). Así que la situación real no permitió el uso de símbolos de enum .


(*) Esto no es, para decirlo cortésmente, una buena manera de hacerlo. El código se basa en el comstackdor para condensar las dos cadenas en una ubicación en la tabla de cadenas del progtwig comstackdo. Esta es una optimización típica (incluso se podría decir que es obvia ) para el comstackdor, pero no está garantizada por ningún estándar. Sería mejor (aunque más detallado) asignar el literal de cadena a una variable char * y usar la variable en ambos lugares. Puede (y probablemente debería) probar el resultado de strstr para `NULL antes de hacer algo con el resultado.

También puedes usar enumeraciones:

 enum MathOps {PLUS, MINUS, MULTIPLY}; MPI mathfunc(MPI x, enum MathOps operation, MPI y) { switch(operation){ case PLUS: //... break; case MINUS: //... break; case MULTIPLAY: // .... break; //etc. } Call: mathfunc(x,PLUS,y) 

Lo bueno de este enfoque es que puede ver fácilmente en la parte superior del archivo las operaciones que su función admitirá. El comstackdor también se quejará si agrega una enumeración pero no la agrega al caso de cambio, lo que puede ser bueno.

EDITAR: ejemplo en vivo: http://ideone.com/GCJ9ro