I'm writing some math routines in a C program for multi-precision integers and I want to be able to easily write expressions, but handle the math with my own function. So I want some way that lets me do this:
MPI x=mpi(5),y=mpi(6),z;
z=mpimath(x,+,y);
Is this possible in C by encoding the character somehow? I know there's no operator overloading so it has to be a function call, and the +
-sign cannot be part of the function name.
Yes, it is possible.
You can interface to your function using a macro. A macro gives you extra powers over the physical appearance of the code. In particular, you can stringify an argument. And you can pass any complete C token as an argument to a macro.
So do something like this:
#define mpimath(X,F,Y) (mpimath)(X,#F,Y) /* stringify F */
Then define your function to accept a char *
parameter. This will result in the string "+"
for the argument +
. By using the same name for the macro, calls to the function are intercepted by this macro so a call like this:
mpimath(p,*,r) /* macro invocation */
is expanded to
(mpimath)(p,"*",r) /* function call */
. The parens around the function name are not strictly necessary here, since a macro is not allowed to be recursive, it will expand to the right thing. But wrapping parens is also the way to explicitly call the function bypassing any macro definitions, so I find it helps self-document the code to add them here.
You can use something like char *ops="+-*/"; int op=strstr(ops, f)-ops;
to map the string to a small integer (*) which can then be used to index a function-table. Or you can dereference the string to get a char
which you can use in a switch
.
MPI mpimath(MPI x, char *f, MPI y){
switch(*f){
case '+': //...
break;
case '-': //...
break;
//etc.
}
Or you can move the dereferencing back into the macro. It looks a little weird in the macro. But I think it makes the function look nicer.
#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.
}
}
Edit: Some details about the actual code that gave rise to this share-your-knowledge q/a pair.
The motivation for the passing the operator as a char
arose indirectly, but never in the simplified form shown in the question. The current use of macro looks like this for the +
function:
BIN_MATH_FUNC(+,AV(z)[i],AV(a)[i],AV(w)[i],plusover,plusdomainI,plusdomainD)
and the macro also directly handles native types like int
and double
. So the framework that the mpi function needed to fit was already set up to distinguish operations by their actual C operator (as a macro argument). So the real situation didn't allow for the use of enum
symbols.
(*) This is not, to put it politely, a good way to do it. The code relies upon the compiler to condense the two strings into one location in the compiled program's string-table. This is a typical (one might even say obvious) optimization for the compiler to do, but is it not guaranteed by any standard. It would be better (though more verbose) to assign the string literal to a You can (and probably should) test the result of char *
variable and use the variable in both places.strstr
for `NULL before doing anything with the result.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With