can the pre-processor convert string literals into chars?

Discussion in 'C++' started by steve.lorimer@gmail.com, Mar 29, 2007.

  1. Guest

    Hi

    Thanks for taking the time to read this.

    I'm looking for a pre-processor command that will allow me to resolve
    const
    strings into const char literals at compile time.

    Looking at the code below, I can take 5 characters and create a const
    uint64_t value at compile time.
    I can then create a switch statement that has these const values as
    the
    various cases.
    Since each case resolves to an integer constant value at compile
    time,
    this switch statement is valid.

    const uint64_t val1 = (static_cast<uint64_t>('S') << 32) | // S
    (static_cast<uint64_t>('T') << 24) | // T
    (static_cast<uint64_t>('A') << 16) | // A
    (static_cast<uint64_t>('R') << 8) | // R
    (static_cast<uint64_t>('T')); // T

    const char c1 = 'S', c2 = 'T', c3 = 'O', c4 = 'P';
    const uint64_t val2 = (static_cast<uint64_t>(c1) << 32) | // S
    (static_cast<uint64_t>(c2) << 24) | // T
    (static_cast<uint64_t>(c3) << 16) | // O
    (static_cast<uint64_t>(c4) << 8) | // P
    (static_cast<uint64_t>(0));

    uint64_t input = 0;
    switch (input)
    {
    case val1: printf("input=val1\n"); break;
    case val2: printf("input=val2\n"); break;
    default: break;
    }
    //--------------------------------------------------------------------------

    Now I attempt to repeat the above code, but instead of using literal
    character
    values, I use a const string literal.
    gcc returns the following error:

    error: case label does not reduce to an integer constant

    So I guess the compiler is not able to resolve the index into the char
    array at compile time.


    const char* const str1 = "START";
    const uint64_t val1 = (static_cast<uint64_t>(str1[0]) << 32) | //
    S
    (static_cast<uint64_t>(str1[1]) << 24) | //
    T
    (static_cast<uint64_t>(str1[2]) << 16) | //
    A
    (static_cast<uint64_t>(str1[3]) << 8) | //
    R
    (static_cast<uint64_t>(str1[4])); //
    T

    const char* const str2 = "STOP";
    const uint64_t val2 = (static_cast<uint64_t>(str2[0]) << 32) | //
    S
    (static_cast<uint64_t>(str2[1]) << 24) | //
    T
    (static_cast<uint64_t>(str2[2]) << 16) | //
    O
    (static_cast<uint64_t>(str2[3]) << 8) | //
    P
    (static_cast<uint64_t>(str2[4]));

    uint64_t input = 0;
    switch (input)
    {
    case val1: printf("input=val1\n"); break;
    case val2: printf("input=val2\n"); break;
    default: break;
    }
    //--------------------------------------------------------------------------

    What I actually have is a text file containing many unique input
    strings,
    each a maximum of 5 characters long.
    Each of these input strings has a corresponding name and a value that
    it maps to. I'd like to be able to create a switch statement with a
    case for each of the
    possible input strings which returns the associated value.
    At run-time, I can create a uint64_t value from any 5 character input
    string and run the value through my case statement to get a return
    value. Obviously performance wise this is far better than:
    if (strncmp(...))
    return ...
    else
    if (strncmp(...))
    return ...
    else
    ad infinitum


    Please see my example data below:

    << input_values.txt >>
    MACRO1(DO_START, "START", enum_val_start)
    MACRO1(DO_STOP, "STOP", enum_val_stop)

    // create const values
    #undef MACRO1
    #define MACRO1(NAME, INPUT, VALUE) \
    const uint64_t val_##NAME = (static_cast<uint64_t>(INPUT[0])
    << 32) | \
    (static_cast<uint64_t>(INPUT[1])
    << 24) | \
    (static_cast<uint64_t>(INPUT[2])
    << 16) | \
    (static_cast<uint64_t>(INPUT[3])
    << 8) | \
    (static_cast<uint64_t>(INPUT[4]));
    #include "input_values.txt"

    // create switch statement containing above const values
    #undef MACRO1
    #define MACRO1(NAME, INPUT, VALUE) \
    case val_##NAME: return VALUE;

    switch (val)
    {
    #include "input_value.txt"
    default: break;
    }
    //--------------------------------------------------------------------------

    TIA for your help
     
    , Mar 29, 2007
    #1
    1. Advertising

  2. Jack Klein Guest

    On 29 Mar 2007 07:06:38 -0700, wrote in
    comp.lang.c++:

    > Hi
    >
    > Thanks for taking the time to read this.


    I would have thanked you for not posting it multiple times, but oops!,
    you did.

    And then you waste time and bandwidth arguing with someone who
    responds to you because "every microsecond counts", and you complain
    you can't test your claims about relative efficiency because it's too
    hard to manually build code the way you want to.

    You want something like this:

    > const uint64_t val1 = (static_cast<uint64_t>('S') << 32) | // S
    > (static_cast<uint64_t>('T') << 24) | // T
    > (static_cast<uint64_t>('A') << 16) | // A
    > (static_cast<uint64_t>('R') << 8) | // R
    > (static_cast<uint64_t>('T')); // T


    [snip]

    From this:

    > Now I attempt to repeat the above code, but instead of using literal
    > character
    > values, I use a const string literal.
    > gcc returns the following error:
    >
    > error: case label does not reduce to an integer constant
    >
    > So I guess the compiler is not able to resolve the index into the char
    > array at compile time.
    >
    > const char* const str1 = "START";
    > const uint64_t val1 = (static_cast<uint64_t>(str1[0]) << 32) | //
    > S
    > (static_cast<uint64_t>(str1[1]) << 24) | //
    > T
    > (static_cast<uint64_t>(str1[2]) << 16) | //
    > A
    > (static_cast<uint64_t>(str1[3]) << 8) | //
    > R
    > (static_cast<uint64_t>(str1[4])); //
    > T


    You want to torture and abuse the preprocessor, always a bad idea, to
    make the second case, above, work like the first case, because you
    have just too many literal strings to code by hand, poor you.

    Well are you a programmer or just a whiner?

    Write a program that reads a text file consisting of a single word of
    five characters or less per line, and writes another text file with a
    name like "my_constants.h".

    How hard can it possible be to write code that reads "START" and
    writes output text identical to the first quoted portion above?

    Writing a small utility program is almost always a better choice than
    torturing the preprocessor.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://c-faq.com/
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
     
    Jack Klein, Mar 29, 2007
    #2
    1. Advertising

  3. James Kanze Guest

    Jack Klein wrote:
    > On 29 Mar 2007 07:06:38 -0700, wrote in
    > comp.lang.c++:


    [...]
    > Writing a small utility program is almost always a better choice than
    > torturing the preprocessor.


    Or using unreadable templates:). (A solution using template
    meta-programming is justifiable when you need information only
    available within the compiler, e.g. concerning types.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Mar 30, 2007
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Goche
    Replies:
    8
    Views:
    16,574
  2. pre-processor string replacement

    , Jan 14, 2007, in forum: C Programming
    Replies:
    11
    Views:
    447
    Thad Smith
    Jan 14, 2007
  3. Replies:
    0
    Views:
    331
  4. Replies:
    10
    Views:
    675
  5. Hongyu
    Replies:
    9
    Views:
    966
    James Kanze
    Aug 8, 2008
Loading...

Share This Page