Long if..else statement

c, if-statement

Solution

Store all of the names and functions in a structure:

struct calcRoutine_t {
  const char *name;
  void (*function)(int, int, int);
} calc_routine[] = {
  { "log",  mpfr_log },
  { "log2", mpfr_log2 },
  { "log10",    mpfr_log10 },
  { "sqrt", mpfr_sqrt },
  { "cbrt", mpfr_cbrt },
  { "abs",  mpfr_abs },
  { "sin",  mpfr_sin },
  { "cos",  mpfr_cos },
  { "csc",  mpfr_csc },
  { "cot",  mpfr_cot },
  { "acos", mpfr_acos },
  { "asin", mpfr_asin },
  { "atan", mpfr_atan },
  { "cosh", mpfr_cosh },
  { "sinh", mpfr_sinh }
};

Loop over the array and use `strcmp` to locate the correct function:

for (i=0; i<sizeof(calc_routine)/sizeof(calc_routine[0]); i++)
{
    if (!strcmp ( calc_routine[i], alnumToc) )
    {
        ARGNUMCHECK( in, 1);
        calc_routine[i].function (num, stack[j-1], MPFR_RNDN);
        CPYRES( 1);
        break;
    }
}

(You can add a flag for 'success' before the `break`, or test if `i == sizeof(calc_routine) /sizeof(calc_routine[0])` at the bottom.)

This has the initial advantage you can add, shuffle, and remove any of the sub-routines at will.

As soon as you decided on a final set of names/functions, sort them once by name and then use `bsearch` instead of this loop. On success, `bsearch` will point to the correct structure member and you can call its associated function right away; on failure, `bsearch` will return `NULL`.

Add

As noted in a comment, some functions may need more arguments than 1. This number can be stored in the struct `calcRoutine_t` as well, to be tested in the loop.

Problem

How do I reduce long if..else statement such as this one? ``` if( strcmp( alnumToc, "log") == 0){ ARGNUMCHECK( in, 1); mpfr_log( num, stack[j-1], MPFR_RNDN); CPYRES( 1); } else if( strcmp( alnumToc, "log2") == 0){ ARGNUMCHECK( in, 1); mpfr_log2( num, stack[j-1], MPFR_RNDN); CPYRES( 1); } else if( strcmp( alnumToc, "log10") == 0){ ARGNUMCHECK( in, 1); mpfr_log10( num, stack[j-1], MPFR_RNDN); CPYRES( 1); } else if( strcmp( alnumToc, "sqrt") == 0){ ARGNUMCHECK( in, 1); mpfr_sqrt( num, stack[j-1], MPFR_RNDN); CPYRES( 1); } else if( strcmp( alnumToc, "cbrt") == 0){ ARGNUMCHECK( in, 1); mpfr_cbrt( num, stack[j-1], MPFR_RNDN); CPYRES( 1); } else if( strcmp( alnumToc, "abs") == 0){ ARGNUMCHECK( in, 1); mpfr_abs( num, stack[j-1], MPFR_RNDN); CPYRES( 1); } else if( strcmp( alnumToc, "sin") == 0){ ARGNUMCHECK( in, 1); mpfr_sin( num, stack[j-1], MPFR_RNDN); CPYRES( 1); } else if( strcmp( alnumToc, "cos") == 0){ ARGNUMCHECK( in, 1); mpfr_cos( num, stack[j-1], MPFR_RNDN); CPYRES( 1); } else if( strcmp( alnumToc, "csc") == 0){ ARGNUMCHECK( in, 1); mpfr_csc( num, stack[j-1], MPFR_RNDN); CPYRES( 1); } else if( strcmp( alnumToc, "cot") == 0){ ARGNUMCHECK( in, 1); mpfr_cot( num, stack[j-1], MPFR_RNDN); CPYRES( 1); } else if( strcmp( alnumToc, "acos") == 0){ ARGNUMCHECK( in, 1); mpfr_acos( num, stack[j-1], MPFR_RNDN); CPYRES( 1); } else if( strcmp( alnumToc, "asin") == 0){ ARGNUMCHECK( in, 1); mpfr_asin( num, stack[j-1], MPFR_RNDN); CPYRES( 1); } else if( strcmp( alnumToc, "atan") == 0){ ARGNUMCHECK( in, 1); mpfr_atan( num, stack[j-1], MPFR_RNDN); CPYRES( 1); } else if( strcmp( alnumToc, "cosh") == 0){ ARGNUMCHECK( in, 1); mpfr_cosh( num, stack[j-1], MPFR_RNDN); CPYRES( 1); } else if( strcmp( alnumToc, "sinh") == 0){ ARGNUMCHECK( in, 1); mpfr_sinh( num, stack[j-1], MPFR_RNDN); CPYRES( 1); } ``` It's not just ugly but also slow. I thought of using hashtable with function pointers. Is that good solution? Note: there will be some mpfr functions, that take more arguments, so I can't create just one macro.

Original source

Related problems