Macro lookup table?

Cor Smuts
2004-01-29
2013-03-12
  • Cor Smuts
    Cor Smuts
    2004-01-29

    #define STRING1    "LOG SENT"
    #define STRING2    .......
    .
    .
    .

    #define PRINT_STR(cmd)    (PrintStr(0,0,  STRING ## cmd))

    void menu2Buttons()
      {
        unsigned char uc_literal;
        while(1)
          {
           switch(getKey())
        {
        case 1:     ......
        //PrintStr(0,0,"LOG SENT");
        uc_literal=1;
        break;
        case 2:    ......
        uc_literal=2;
        //PrintStr(0,0,"LOG ERASED");
        break;
        case 3:    .......
        uc_literal=3;            //PrintStr(0,0,"EEPROM CLEARED");
        break;
        case .......
        .
                 .
                 .

        }//switch keypressed
         PRINT_STR(uc_literal);
      }//menu2Buttons()

    OK, what I was basically trying to do here, was assign a string from a macro the the printstr function, which prints the string to an lcd display, instead of having a printstr funtion call inside each case statement, I just wanted to assign uc_literal a value and use macros as a lookup table, to shorten my assembler code, since I have a problem with space at the moment.
    I now realize that the method I tried to use will not work. Is there another way of doing this?

     
    • JC
      JC
      2004-01-29

      This is just one of several ways this can be done.

      static const char *msgs [] =
      {
         { "LOG SENT" },
         { "LOG ERASED" },
         { "LOG TURNED INTO SAWDUST" },
         { "WTF?" },
      }

      //
      //  Using enums makes it easy to insert messages anywhere in the above array,
      //  then insert it's name in the same relative spot below.  Using #defines with
      //   blahblahblah+1 is noisy and cumbersome
      //
      typedef enum
      {
          MSG_LOGSENT = 0,
          MSG_LOGERASED,
          MSG_LOGOTHER,
          MSG_UNKNOWN
      }
      msgNumbers_e;

      void menu2Buttons ()
      {
         msgNumbers_e uc_literal = MSG_UNKNOWN;

        while (1)
        {
           switch (getKey ())
           {
          case 1:
             uc_literal = MSG_SENT;
             break;
          case 2:
             uc_literal = MSG_ERASED;
             break;
          case 3:
             uc_literal = MSG_OTHER;
             break;
          default :
             break;
            }
          }

          PrintStr (0, 0, msgs [uc_literal]);
        }
      }

       
    • Of course, it does not work 'cause the preprocesor macros are runned at compile time not at run time. The problem here is that if you want to display a different string for each key you will have to put all the possible strings in rom so you can choose one at run time. If your uC memory is not enough then you will have to use an external memory, I suggest a I2C memory if you are short of pins.

       
  • workify
    workify
    2012-09-04

    For stuff like that, I prefer to use a method the assures the enums, strings, key codes and cases do not get out of sync.
    But, for this tiny example, it is not so useful:

    #define MSGS(X) \
    X("LOG SENT",MSG_LOGSENT,1) \
    X("LOG ERASED", MSG_LOGERASED,2) \
    X("LOG TURNED INTO SAWDUST",MSG_LOGOTHER,3) \

    #define X(MSG,ENUM,KEY) MSG,
    static const char *msgs  = { MSGS(X) "WTF?" };
    #undef X

    #define X(MSG,ENUM,KEY) ENUM,
    typedef enum { MSGS(X) MSG_UNKNOWN } msgNumbers_e;
    #undef X


    switch (getKey ())
         {
    #define X(MSG,ENUM,KEY) case KEY:  uc_literal = ENUM; break;
         MSGS(X)
    #undef X
         default: uc_literal = MSG_UNKNOWN; break;
         }