Using Strings with a Switch

Environment:

The following macros help to achieve the switch-case on a string.

//////////////////////////////////////////////////////////////
#define STR_SWITCH(str)  {\
        TCHAR* __ps = (TCHAR*)((const TCHAR*)str);\
        while(1) {

#define STR_SWITCH_END()  break; } }

#define STR_CASE(str) if(0 == _tcsicmp(__ps,((const TCHAR*)str)))

#define STR_CASE_EXACT(str)  if( 0 == _tcscmp( __ps, 
                               ((const TCHAR*)str) ) )

#define DEFAULT_CASE()

//////////////////////////////////////////////////////////////

How do you use these macros? Go through the following piece of code.

Myclass::Function()
{
  CString sSwitch("bbbb");
  CString sCase("AAAA");

  STR_SWITCH(sSwitch)      //Start of switch
  {                        //Opening and closing braces
                           //NOT MANDATORY for switch.
  STR_CASE(sCase)
    {                      //Opening and closing braces
                           //MANDATORY for case.
      AfxMessageBox("In first case statement");
      break;               //break has to in braces of case
    }                      //Opening and closing braces
                           //MANDATORY for case.

  break;                   //Illegal break -- The code works,
                           //but the output....?????

  sCase = _T("bbbb");      //Statements allowed here ;)

  STR_CASE_EXACT(sCase)
    {
      AfxMessageBox("In second case statement");
      break;
    }
  DEFAULT_CASE()
    {
                           //Default handling if any
      break;
    }
  }                        //Opening and closing braces
                           //NOT MANDATORY for switch
  STR_SWITCH_END()         //MANDATORY statement
}

STR_CASE() -> Perform a lowercase comparison of strings.
STR_CASE_EXACT() -> Compares strings, matches the
                     case of the characters.
DEFAULT_CASE() -> Default case for the switch.

Note the following requirements:

  1. The "break" statement has to be inside the scope for the STR_CASE, STR_CASE_EXACT, or DEFAULT_CASE.
  2. Fall through for case statements is not allowed with this switch case.
  3. Statements between two cases are allowed. Be careful while modifying the string on which the switch is performed.


Comments

  • more elegant (IMHO) solution

    Posted by Legacy on 09/07/2003 12:00am

    Originally posted by: Old Wolf

    Here is a solution that:
    
    - doesn't require macros for the "case" statements
    - doesn't require magic number cases ("case 0:" etc.)
    - allows for looking up strings efficiently
    - allows for case insensitivity and other conversions
    - differentiates between no-such-string and
    string-valid-but-no-case
    - associates an enum with each string safely (no chance
    of having the enums not match up with the strings)
    - same idea works in both C and C++

    There is a small price for all this: you have to put all your strings into a separate source file, and this source file is a bit ugly.

    Probably you don't want to use my code as-is, but it's the idea that counts and you can modify it to suit what you need to do.

    ------------------------------ FILE ENUMS.H ---------

    #ifndef ENUMS_C
    #define AS(str) str,
    namespace Seasons {
    enum {
    #else
    #define AS(str) vSeasons.push_back(#str);
    #endif
    AS(spring)
    AS(summer)
    AS(autumn)
    AS(winter)

    #ifndef ENUMS_C
    };
    }; // namespace Seasons
    #endif

    #undef AS

    ----------------------- EXAMPLE MAIN PROGRAM ----------
    #include <iostream>
    #include <algorithm> // find()
    #include <vector>
    #include <string>

    #include "enums.h"

    using std::cin;
    using std::cout;
    using std::find;

    // use a hashtable or some other structure
    // if you want better performance than find() on a vector
    std::vector<std::string> vSeasons;

    int main(void)
    {
    #define ENUMS_C
    #include "enums.h"

    std::string s;
    cout << "Enter a season: ";
    cin >> s;

    // do any conversions here
    // s = std::strlower(s);

    // short method (you could make this a #define too if you wanted)
    // switch(find(vSeasons.begin(), vSeasons.end(), s) - vSeasons.begin())

    // long method (differentiates between a string that isn't in the list,
    // and a string that is in the list but doesn't have a "case" entry)
    std::vector<std::string>::iterator i;
    if (vSeasons.end() == (i = find(vSeasons.begin(), vSeasons.end(), s)))
    {
    cout << "unknown season";
    }
    else switch(i - vSeasons.begin())
    {
    case Seasons::spring:
    cout << "spring is in the air" << endl;
    break;

    case Seasons::winter:
    cout << "jack frost is biting" << endl;
    break;

    default:
    cout << "unhandled season" << endl;
    }

    return 0;
    }

    --------------------------------------- END ----

    To do this in plain C (not C++), put the second #include "enums.h" outside of main(), and make it declare an array of const char *seasons[] (instead of pushing onto a vector). Then write some function to search the array for the string, instead of where I used C++'s "find()" algorithm.

    Reply
  • not recommendable

    Posted by Legacy on 05/03/2003 12:00am

    Originally posted by: chen3feng

    It's not a good idea for either perfanmance or mentainment, I think.
    MACRO, macro is a dangerous thing. try your best to avoid using it.

    Reply
  • String switch

    Posted by Legacy on 01/10/2003 12:00am

    Originally posted by: Peter Briody

    At the risk of being hunted down as a c++ poluter, I submit the following routine for string switching which I have been using for years ( mainly because I am too dumb to know any better ).


    Here it is as an example:
    CString StrExt = „Path.zip“;


    LPCSTR lpExt[] = {".zip",".lzh"};
    switch( StrMatchPos(strExt,lpExt,sizeof(lpExt)/sizeof(LPCSTR) ))
    {
    case 0://.zip
    AfxMessageBox("zip");
    break;
    case 1://.lzh
    AfxMessageBox("lzh");
    break;
    default:
    AfxMessageBox("other");
    break;
    }

    The initialisation array provides a good view of what you are doing and the routine is only one line longer than usual.


    Put th�s following routine somewhere central – in your own utilities-dll maybe


    UINT StrMatchPos(LPCSTR lpExp, LPCSTR *lpArray,DWORD dwCount)
    {
    try
    {
    UINT n;
    CString strTmp,strExp = lpExp;

    for ( n = 0; n < dwCount;n++)
    {
    strTmp = lpArray[n];

    if ( strTmp.CompareNoCase(strExp) == 0 )
    return n; // match
    }// for n

    return -1; // no match
    }
    catch(...){return -1;}// Error}

    }

    If you want to make life tough for yourself and try to force c++ to behave in ways for whuch it was not designed then don't let me spoil your fun - and dont bother to write write and tell me !

    Reply
  • Performance note

    Posted by Legacy on 10/05/2002 12:00am

    Originally posted by: Stepan Orlov

    1. I've read carefully nearly all of comments and have found that no one discussed how fast would a code using "string switch" work. The matter is that the a good c/c++ compiler produces code for the switch statement which performs BINARY search to find a matching case. What Swikar Sugandhi offers us works good for a small number of CASEs, but much worse than real switch if there's a lot of CASEs - using these macros will cause a LINEAR search.

    2. One should keep in mind that "string switch" has semantics different from the SWITCH operator - I mean the situation when we don't use the BREAK operator after each CASE.

    Stepan Orlov

    Reply
  • Plz be cool

    Posted by Legacy on 10/02/2002 12:00am

    Originally posted by: Buyung

    Dear all programmer, I would like to remind you that all your Submitted articles or your comments very usefull for me, because I just started to learn VC++. I try to collect your articles with the comments and I am so sad to find some command finger out the others as......remember I am not the only one who started with the language programming...there's thousands and what your are submitted very - very helpfull.
    
    

    Regards
    Buyung

    Reply
  • Optimistis

    Posted by Legacy on 08/12/2002 12:00am

    Originally posted by: Kannan

    A moon without black marks will not looks better. We (this group) should have 1 or 2 members like Eric.

    Reply
  • Not perfect, but it works

    Posted by Legacy on 08/11/2002 12:00am

    Originally posted by: Alex F

    I think CodeGuru is not a proper site to write a negative comments like these.
    Swikar: implementing Fall Trough may be a good reply to Eric and Jimmy.

    Reply
  • It's just bad..

    Posted by Legacy on 08/10/2002 12:00am

    Originally posted by: Jimmy

    Well first, don't do stuff with macros like that. Those who wanted a reference why, try the king, Stroustrup: http://www.research.att.com/~bs/bs_faq2.html#macro
    Doing "switch" isn't THAT bad, but macros are, and having to switch on a string too. Check your design, maybe that you should be using a map or a hash_map instead..

    Reply
  • Why is switch/case not OOP?

    Posted by Legacy on 08/09/2002 12:00am

    Originally posted by: John Wellbelove

    Since starting to program in C++ I've read several C++ books and attended Advance C++ programming courses and this is the first time I've ever heard about 'switch/case' being non-OOP!

    If anyone has a URL of an article which gives a reason why, I would be most interested.

    Reply
  • REALLY REALLY BAD THINGS!!!!!

    Posted by Legacy on 08/08/2002 12:00am

    Originally posted by: Eric

    Please people!!! please don't do that please!! :o(

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • IBM Worklight is a mobile application development platform that lets you extend your business to mobile devices. It is designed to provide an open, comprehensive platform to build, run and manage HTML5, hybrid and native mobile apps.

  • Companies must routinely transfer files and share data to run their business, work with partners, and speed operations. However, many find the traditional approach to file transfer lacks necessary security, is too complex and difficult to manage, does not support the levels of automation needed, and breaks down when addressing the file transfer requirements of new areas like Big Data analytics and mobile applications. This QuinStreet SmartSelect discusses how the changing business environment is making the use …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds