#defines and strings

Discussion in 'C Programming' started by GMM50, Jun 30, 2005.

  1. GMM50

    GMM50 Guest

    Hello:

    I am working on a design that has a large number of messages. These
    messages are saved in the system and used by the system. I need to
    convert from message names to internal storage location.

    I will force a naming convention something like names from SM1001 to
    SM1999. Not all SMxxxx numbers are used. And as the design changes
    old SMxxxx will be deleted and new ones added.

    In the code I use these messages as constants as:
    PlayMsg(SM1023, OutputChannel, Volume);
    So I'm planning to use a define to convert SM1023 to the internal
    storage number (= location).

    #define SM1023 19 // Hello Message

    But then when the user downloads a message I need to programatically
    determine it's internal storage number (= location).

    So a table of structures
    struct MSG_CVRT {
    int msg;
    int loc;
    }

    struct MSG_CVRG MsgTbl[] = {
    1023, 19; // Hello Message
    0, 0;
    }

    And I can look for MsgTbl.msg and then extract the location.

    My problem is I now have data in two places and they will get out of
    sync. Anyone come across this issue and have advice.

    This is an embedded system so memory usage and speed of operation are
    considered.

    Thanks in advance
    george
    GMM50, Jun 30, 2005
    #1
    1. Advertising

  2. In article <>,
    GMM50 <> wrote:
    >In the code I use these messages as constants as:
    > PlayMsg(SM1023, OutputChannel, Volume);
    >So I'm planning to use a define to convert SM1023 to the internal
    >storage number (= location).


    >#define SM1023 19 // Hello Message


    >But then when the user downloads a message I need to programatically
    >determine it's internal storage number (= location).


    >struct MSG_CVRG MsgTbl[] = {
    > 1023, 19; // Hello Message
    > 0, 0;
    >}


    >My problem is I now have data in two places and they will get out of
    >sync.



    Perhaps I'm missing something, but why not use

    struct MSG_CVRG MsgTbl[] = {
    1023, SM1023, // Hello Message
    0, 0,
    };

    (Note: semicolons converted to commas)


    Potentially you might also want to consider

    #define PASTE(T1,T1) T1##T2
    #define DclMsg(N) {N, PASTE(SM,N)}

    struct MSG_CVRG MsgTbl[] = {
    DclMsg(1023),
    DclMsg(1196),
    DclMsg(1197),
    {0, 0},
    };


    Also, you might not need the trailing {0, 0} as you can take
    sizeof(MsgTabl) / sizeof(struct MSG_CVRG)
    to find out how many elements there are.
    --
    The rule of thumb for speed is:

    1. If it doesn't work then speed doesn't matter. -- Christian Bau
    Walter Roberson, Jun 30, 2005
    #2
    1. Advertising

  3. GMM50

    Eric Sosman Guest

    GMM50 wrote:
    > Hello:
    >
    > I am working on a design that has a large number of messages. These
    > messages are saved in the system and used by the system. I need to
    > convert from message names to internal storage location.
    >
    > I will force a naming convention something like names from SM1001 to
    > SM1999. Not all SMxxxx numbers are used. And as the design changes
    > old SMxxxx will be deleted and new ones added.
    >
    > In the code I use these messages as constants as:
    > PlayMsg(SM1023, OutputChannel, Volume);
    > So I'm planning to use a define to convert SM1023 to the internal
    > storage number (= location).
    >
    > #define SM1023 19 // Hello Message
    >
    > But then when the user downloads a message I need to programatically
    > determine it's internal storage number (= location).
    >
    > So a table of structures
    > struct MSG_CVRT {
    > int msg;
    > int loc;
    > }
    >
    > struct MSG_CVRG MsgTbl[] = {
    > 1023, 19; // Hello Message
    > 0, 0;
    > }
    >
    > And I can look for MsgTbl.msg and then extract the location.
    >
    > My problem is I now have data in two places and they will get out of
    > sync. Anyone come across this issue and have advice.


    I'm not 100% sure I understand exactly what happens when
    "the user downloads a message." The download must be tagged
    with some kind of identifier, which I'm guessing is the numeric
    value 1023 -- if that's not it, then just disregard the rest
    of this message.

    Your problem (if I've understood it) is how to keep the
    #define and the translation table synchronized, that is, how
    to be sure that if either 1023 or 19 changes it changes in
    both places simultaneously.

    One way is to eliminate the #define, or to replace it
    with something vacuous like `#define SM1023 1023'. Functions
    like PlayMsg() could be changed so they didn't understand the
    first argument as a "storage number," but as a value to be
    looked up in MsgTbl[]. According to your description there
    will be fewer than one thousand entries in the table, so the
    lookup cost will be small (binary search will average fewer
    than nine probes).

    Another way is to retain both, but to generate them from
    a single common source. For example, you might treat MsgTbl[]
    as The Authoritative Word, and run a little "helper" program
    to generate a .h file from the table's contents. For more
    complicated situations, the "helper" could read some other
    kind of data file and generate both the #define lines and the
    content of MsgTbl[], but that might be overkill in your case.

    --
    Eric Sosman, Jun 30, 2005
    #3
  4. GMM50

    GMM50 Guest

    > I'm not 100% sure I understand exactly what happens when
    > "the user downloads a message." The download must be tagged
    > with some kind of identifier, which I'm guessing is the numeric
    > value 1023 -- if that's not it, then just disregard the rest
    > of this message.


    I need to convert from the message being downloaded (ie SME1023) into
    the internal numbering system and that message name comes in the
    download port as a text string.

    > Your problem (if I've understood it) is how to keep the
    > #define and the translation table synchronized, that is, how
    > to be sure that if either 1023 or 19 changes it changes in
    > both places simultaneously.


    Exactly.

    > One way is to eliminate the #define, or to replace it
    > with something vacuous like `#define SM1023 1023'. Functions
    > like PlayMsg() could be changed so they didn't understand the
    > first argument as a "storage number," but as a value to be
    > looked up in MsgTbl[]. According to your description there
    > will be fewer than one thousand entries in the table, so the
    > lookup cost will be small (binary search will average fewer
    > than nine probes).


    That works for the internal playing of messages but not the donwload
    event.

    > Another way is to retain both, but to generate them from
    > a single common source. For example, you might treat MsgTbl[]
    > as The Authoritative Word, and run a little "helper" program
    > to generate a .h file from the table's contents. For more
    > complicated situations, the "helper" could read some other
    > kind of data file and generate both the #define lines and the
    > content of MsgTbl[], but that might be overkill in your case.
    >
    > --
    >


    I've come to the same conclusion. I have a .h file

    #define SME1001 2003 // Good Morning Welcome message

    And then a program that converts the defines into a table. So one file
    contains all the facts. I'm also considering putting the conversion
    code in the product as one less it item forget about.

    thanks
    GMM50, Jun 30, 2005
    #4
  5. GMM50

    Eric Sosman Guest

    GMM50 wrote:
    >Eric Sosman wrote:
    >>[...]
    >> One way is to eliminate the #define, or to replace it
    >>with something vacuous like `#define SM1023 1023'. Functions
    >>like PlayMsg() could be changed so they didn't understand the
    >>first argument as a "storage number," but as a value to be
    >>looked up in MsgTbl[]. According to your description there
    >>will be fewer than one thousand entries in the table, so the
    >>lookup cost will be small (binary search will average fewer
    >>than nine probes).

    >
    > That works for the internal playing of messages but not the donwload
    > event.


    I don't see why not: it's exactly the mechanism you described
    in your original message! The user downloads a message tagged
    with the string SM1023; you extract the number 1023 from this
    and look it up in MsgTbl[] to learn the "storage number." My
    suggestion amounts to always trafficking in the SMxxxx numbers,
    forcing *everybody* to go through MsgTbl[] and eliminating all
    other routes. If there's only one route, you don't need to
    worry two different routes having different destinations.

    --
    Eric Sosman, Jun 30, 2005
    #5
  6. GMM50

    Suman Guest

    Walter Roberson wrote:
    > In article <>,

    [snip]...

    > #define PASTE(T1,T1) T1##T2

    ^
    #define PASTE(T1,T2) T1##T2
    > #define DclMsg(N) {N, PASTE(SM,N)}


    The braces give me a problem if I try to use them in printf.
    Would parentheses be terribly wrong here?

    > struct MSG_CVRG MsgTbl[] = {

    [snip]
    Suman, Jul 1, 2005
    #6
  7. GMM50

    GMM50 Guest

    I agree with you on the download case when the SM1234 is presented as
    data on a download port.

    The other use is of these names in in the code when I try to use them
    in PlayMsg(SM1023, OutputChannel, Volume);

    In the above example the messages names are used as defines which can't
    go through the MsgTbl[].

    I could use PlayMsg("SM1023", OutputChannel, Volume);
    But then I need to convert "SM1023" to a numberic and use the table for
    each call to PlayMsg(). Larger slower code but then only one
    controling MsgTbl[].

    Am i missing something. Wouldn't be the first time.
    your thoughts.
    GMM50, Jul 1, 2005
    #7
  8. GMM50

    Eric Sosman Guest

    GMM50 wrote:
    > I agree with you on the download case when the SM1234 is presented as
    > data on a download port.
    >
    > The other use is of these names in in the code when I try to use them
    > in PlayMsg(SM1023, OutputChannel, Volume);
    >
    > In the above example the messages names are used as defines which can't
    > go through the MsgTbl[].
    >
    > I could use PlayMsg("SM1023", OutputChannel, Volume);
    > But then I need to convert "SM1023" to a numberic and use the table for
    > each call to PlayMsg(). Larger slower code but then only one
    > controling MsgTbl[].
    >
    > Am i missing something. Wouldn't be the first time.
    > your thoughts.


    Perhaps I'm the one who's missing something (it won't
    be the last time). In your original post, you wrote

    > So a table of structures
    > struct MSG_CVRT {
    > int msg;
    > int loc;
    > }
    >
    > struct MSG_CVRG MsgTbl[] = {
    > 1023, 19; // Hello Message
    > 0, 0;
    > }
    >
    > And I can look for MsgTbl.msg and then extract the location.


    .... which means you know how to take the number 1023 and
    find the corresponding "location" 19. Fine. Now, your
    current implementation of PlayMsg() probably looks like

    void PlayMsg(int loc, channel_t chan, volume_t vol) {
    /* machine-specific code to play the message
    * at loc on channel chan at volume vol
    */
    }

    I'm suggesting you change the way PlayMsg() is defined and
    implemented, so that the first argument is not the "location"
    but the message ID. You'd have

    void PlayMsg(int msg, channel_t chan, volume_t vol) {
    int loc;
    loc = look_up_in_MsgTbl(msg);
    /* machine-specific code as before, using
    * the loc value from MsgTbl[]
    */
    }

    (If PlayMsg() isn't something you can modify, write a
    "wrapper" function like MessagePlay() that accepts a
    message ID, looks it up in MsgTbl[] to find the "location,"
    and calls PlayMsg() with the result. Forbid any calls to
    PlayMsg() except the one in MessagePlay() itself.)

    The benefit is that there's now only one "designator"
    for a message (the 1023 of your example) rather than two
    (1023 and 19). PlayMsg() and related low-level functions
    like StoreNewMsg() are the only users of 19, and they are
    never handed it directly but always get it by looking up
    1023 in MsgTbl[]. Thus, MsgTbl[] is the one and only
    place where the 1023<->19 connection is made, and you need
    never worry about two "authorities" that might disagree.
    MsgTbl[] is always in step with itself.

    The drawback is that you must spend cycles performing
    the lookup every time you play (or do anything else with)
    a message. Lookup time in a table with no more than 1000
    entries is almost certainly trivial; the 4MHz 8-bit Z80
    machine I had twenty years ago could have done it in less
    than 200 microseconds, maybe less than 100. I seriously
    doubt that this "drawback" is in the least bit important.

    --
    Eric Sosman, Jul 1, 2005
    #8
    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. exquisitus
    Replies:
    12
    Views:
    22,324
    Tilman Bohn
    Feb 19, 2005
  2. Replies:
    2
    Views:
    463
    marbac
    May 8, 2005
  3. theotyflos
    Replies:
    3
    Views:
    450
    Thomas Matthews
    Feb 19, 2004
  4. Brand Bogard

    Ansi standard with #defines and \ character

    Brand Bogard, May 9, 2006, in forum: C Programming
    Replies:
    4
    Views:
    262
    Keith Thompson
    May 10, 2006
  5. Ben

    Strings, Strings and Damned Strings

    Ben, Jun 22, 2006, in forum: C Programming
    Replies:
    14
    Views:
    733
    Malcolm
    Jun 24, 2006
Loading...

Share This Page