Globally unique enums or macro values?

Discussion in 'C Programming' started by userblue@btconnect.com, May 9, 2006.

  1. Guest

    Hi
    Does anyone know if there is a way to define what is effectively a
    single globally visible, enumerated list whilst actually defining the
    entries across several different modules?
    or somehow do a similar thing with macros.

    Details:
    I have a c project to fit into a small microprocessor and need to save
    some ram. I have a significant number of flags all over the place that
    currently use whole byte storage. I thought if I had a way to define a
    list of numerically sequential flag names, I could assign a single
    chunk of ram and a simple function to access the relevant flags as
    single bits. I need to be able to define the different flag names
    within their relevent modules because some modules may be removed at
    compile time using pre-processor directives.
    This code is subject to continuous updating and I just can't find a
    bomb proof way of ensuring the values are unique and sequential with no
    gaps.

    Any ideas?
    Thanks
    Cliff
    , May 9, 2006
    #1
    1. Advertising

  2. Ian Collins Guest

    wrote:
    > Hi
    > Does anyone know if there is a way to define what is effectively a
    > single globally visible, enumerated list whilst actually defining the
    > entries across several different modules?
    > or somehow do a similar thing with macros.
    >
    > Details:
    > I have a c project to fit into a small microprocessor and need to save
    > some ram. I have a significant number of flags all over the place that
    > currently use whole byte storage. I thought if I had a way to define a
    > list of numerically sequential flag names, I could assign a single
    > chunk of ram and a simple function to access the relevant flags as
    > single bits. I need to be able to define the different flag names
    > within their relevent modules because some modules may be removed at
    > compile time using pre-processor directives.
    > This code is subject to continuous updating and I just can't find a
    > bomb proof way of ensuring the values are unique and sequential with no
    > gaps.
    >

    Could you use something like

    struct flags
    {
    uint8_t flag1 : 1;
    uint8_t flag2 : 1;
    uint8_t flag3 : 1;
    uint8_t flag4 : 1;
    uint8_t flag5 : 1;
    };

    --
    Ian Collins.
    Ian Collins, May 9, 2006
    #2
    1. Advertising

  3. Guest

    Thanks Ian. I thought of that, but the problem here is that as well as
    knowing the flag name I also have to remember which structure i put it
    in.
    Thanks
    , May 9, 2006
    #3
  4. Ian Collins <> writes:
    > wrote:
    >> Does anyone know if there is a way to define what is effectively a
    >> single globally visible, enumerated list whilst actually defining the
    >> entries across several different modules?
    >> or somehow do a similar thing with macros.
    >>
    >> Details:
    >> I have a c project to fit into a small microprocessor and need to save
    >> some ram. I have a significant number of flags all over the place that
    >> currently use whole byte storage. I thought if I had a way to define a
    >> list of numerically sequential flag names, I could assign a single
    >> chunk of ram and a simple function to access the relevant flags as
    >> single bits. I need to be able to define the different flag names
    >> within their relevent modules because some modules may be removed at
    >> compile time using pre-processor directives.
    >> This code is subject to continuous updating and I just can't find a
    >> bomb proof way of ensuring the values are unique and sequential with no
    >> gaps.
    >>

    > Could you use something like
    >
    > struct flags
    > {
    > uint8_t flag1 : 1;
    > uint8_t flag2 : 1;
    > uint8_t flag3 : 1;
    > uint8_t flag4 : 1;
    > uint8_t flag5 : 1;
    > };


    The only portable types for bit fields are int, signed int, unsigned
    int, and (C99 only) _Bool.

    Also, it's likely that accessing a bit field requires more code than
    accessing a whole byte. Any savings in data space by packing multiple
    flags int a byte might be lost in the increase in code size. (If code
    and data are in separate address spaces, the tradeoff is more
    complex.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, May 9, 2006
    #4
  5. Guest

    Code space (flash memory) is quite large at 64K, its the ram that's
    precious, a meagre 1K. If I could clump the flags together in a single
    block then the code to access them would be fairly trivial. Probably
    do it as a macro something like (untested):

    #define GetFlag(Flag) (FlagRam[(Flag>>3)] & (1<<(Flag&7)) ? 1 : 0

    If only I could define those flags :-(
    , May 9, 2006
    #5
  6. Ian Collins Guest

    wrote:
    > Thanks Ian. I thought of that, but the problem here is that as well as
    > knowing the flag name I also have to remember which structure i put it
    > in.


    You could put them all in the same one!

    --
    Ian Collins.
    Ian Collins, May 9, 2006
    #6
  7. <> wrote in message
    news:...
    > Hi
    > Does anyone know if there is a way to define what is effectively a
    > single globally visible, enumerated list whilst actually defining the
    > entries across several different modules?
    > or somehow do a similar thing with macros.
    >


    The usual method with macros is a single master header with OR'able and
    AND'able values.

    "master.h"
    #define ASDF 0x01
    #define ASDF 0x02
    #define ASDF 0x04
    #define ASDF 0x08

    Macros can work but get really messy because if you can't #undef until after
    the master header is included. This requires the use of alot of extra
    defines to calculate the number of useful defines which were defined.

    "master.h"
    #define OFFSET 0
    /* just comment out the one module define you don't need */
    /* each central group of macros will be numbered sequentially */
    //#define InclMod0 1
    #define InclMod1 1
    #define InclMod2 1

    #ifdef InclMod0
    #ifndef OFFSET
    #define OFFSET 0
    #endif
    #define ASDFT (OFFSET)
    #define ZXCVC (ASDFT+1)
    #define QWERS (ZXCVC+1)
    #define DFGHR (QWERS+1)
    #ifndef MOD0
    #define MOD0 (DFGHR-OFFSET)
    #endif
    #endif

    #ifdef InclMod1
    #ifndef OFFSET
    #define OFFSET 0
    #endif
    #ifndef MOD0
    #define MOD0 0
    #endif
    #define ASDF (OFFSET+MOD0+1)
    #define ZXCV (ASDF+1)
    #define QWER (ZXCV+1)
    #define DFGH (QWER+1)
    #ifndef MOD1
    #define MOD1 (DFGH-OFFSET-MOD0-1)
    #endif
    #endif

    #ifdef InclMod2
    #ifndef OFFSET
    #define OFFSET 0
    #endif
    #ifndef MOD0
    #define MOD0 0
    #endif
    #ifndef MOD1
    #define MOD1 0
    #endif
    #define FGH (OFFSET+MOD0+MOD1+1)
    #define UIO (FGH+1)
    #define QWE (UIO+1)
    #define JKL (QWE+1)
    #ifndef MOD2
    #define MOD2 (JKL-OFFSET-MOD0-MOD1-1)
    #endif
    #endif

    Of course, if I _actually_ needed to do that, I'd definately try to shorten
    the names as much as possible.


    Rod Pemberton
    Rod Pemberton, May 9, 2006
    #7
  8. Thad Smith Guest

    wrote:
    > Code space (flash memory) is quite large at 64K, its the ram that's
    > precious, a meagre 1K. If I could clump the flags together in a single
    > block then the code to access them would be fairly trivial. Probably
    > do it as a macro something like (untested):
    >
    > #define GetFlag(Flag) (FlagRam[(Flag>>3)] & (1<<(Flag&7)) ? 1 : 0


    You could use macros such as that or write access functions which would
    be smaller, but slower.

    First, some compilers, specifically for 8051, which supports bit access,
    has a separate data type for a bit variable, which the linker will
    allocate for all the linked modules. The 8051 is limited to 128 bits
    for direct bit access. Other compiler/linker implementations probably
    don't have this level of support for bit variable allocation.

    You can use bitfields within each module. It will combine all the bits
    within the module into a structure that is rounded up to the next full
    increment used for structs, probably 8, 16, or 32 bits.

    Here's another approach to save even more space:
    Write a preprocessor that will collect declarations from the files that
    you will include for a specific build and generate a header file that
    defines a structure containing all the bit-fields.

    [ Module 1 ]

    #ifdef USEGLOBALBITS
    #include "globalbits.h"
    #else
    struct {
    int:1 m1flaga;
    int:1 m1flagb;
    ...
    } m1flags;
    #endif
    ....
    /* use the bit variables */
    if (m1flags.m1flaga){
    m1flags.m1flagb = 0;
    }

    [ globalbits.h ]
    /* This file is automatically generated. Do not edit. */
    struct {
    /* declarations from module1.c */
    #define m1flags globalflags
    int:1 m1flaga;
    int:1 m1flagb;
    /* declarations from module3.c */
    #define m2flags globalflags
    int:1 m3flagx;
    int:1 m2flagy;
    ...
    } globalbittype;

    extern globalbittype globalflags;

    The preprocessor would take as parameters the names of the modules to be
    included. It would then scan those modules looking for the specific
    declarations for globalflags ("#ifndef GLOBALBITS" to "#endif"), picking
    out the bit declarations. It defines a single struct containing all the
    bitfields. One caveat is that the bitfield names must all be unique.
    The strict identifier format used above is not required, so you can use
    whatever names you want.

    The reason for the #ifdef is that the modules will compile on their own
    if USEGLOBALBITS is not defined, but bits from separate modules will not
    be combined within a single bitfield. You can use that before you have
    the preprocessor working.

    When you have the preprocessor working have your script or makefile run
    the preprocessor, specifying the modules to be included, then compile
    and link the separate code files. Viola -- minimum RAM for bit variables.

    The preprocessor doesn't need to be able to do general parsing -- only
    recognizing the delimiters for the sections that hold the definitions.

    --
    Thad
    Thad Smith, May 9, 2006
    #8
  9. Guest

    Thad, thanks for the suggestion, it looks interresting. I'll
    investigate and let you know how I get on.
    , May 9, 2006
    #9
  10. Guest

    Thad. Thanks for your suggestion. I've not actually done it like you
    said, but you prompted me in the right direction. The idea of a master
    flag file wrapped in some pre-processor defs is the key. Using this I
    can achieve my preferred goal of a single global enum list whilst
    having the entries defined in separate module headers. This way any
    module can see all the flags from all modules.

    The only caveats being the names must be unique (as you suggested) and
    I must pull in every header with flag definition into the master file.
    This is no problem because the compiler won't let me get away with
    either of them :)

    I tried it out in a simple dos app and it appears to work fine. I post
    the code here for anyone interested.
    There is the main code "Main.c", the master flag file
    "MasterFlags.h" file plus three modules M1, M2 & M3 (M2 & 3 don't
    contain any code).

    //--------- Main.c ---------
    #include <stdio.h>
    #include "M1.h"

    #define GET_FLAG_ENUMS
    #include "MasterFlags.h"
    #undef GET_FLAG_ENUMS

    // Define ram to store flags in
    unsigned char Flags[ (TOTAL_FLAG_COUNT / 8 ) + 1 ] = {0};

    // Test the theory
    unsigned char TestEnums[ TOTAL_FLAG_COUNT ];

    int main(int argc, char* argv[])
    {
    int i;
    printf("%d Flags Defined\n", TOTAL_FLAG_COUNT );

    TestEnums[ 0 ] = M1_Flag_This ;
    TestEnums[ 1 ] = M1_Flag_That ;
    TestEnums[ 2 ] = M1_Flag_TheOther ;
    TestEnums[ 3 ] = M2_Flag_Quick ;
    TestEnums[ 4 ] = M2_Flag_Brown ;
    TestEnums[ 5 ] = M2_Flag_Fox ;
    TestEnums[ 6 ] = M3_Flag_Red ;
    TestEnums[ 7 ] = M3_Flag_Green ;
    TestEnums[ 8 ] = M3_Flag_Blue ;

    for ( i = 0; i < TOTAL_FLAG_COUNT ; i++ )
    {
    printf( "%d, ", TestEnums );
    }
    i = M1_Func();
    printf( "\ni = %d", i );
    scanf("%d",i);

    return 0;
    }
    //---------- END ----------

    //------ MasterFlags.h ------
    #ifndef MASTERFLAGFILEH
    #define MASTERFLAGFILEH

    #define GET_FLAG_ENUMS

    enum {
    #include "M1.h"
    #include "M2.h"
    #include "M3.h"
    TOTAL_FLAG_COUNT
    };

    #undef GET_FLAG_ENUMS

    #endif // MASTERFLAGFILEH
    //---------- END ----------

    //---------- M1.c ----------

    #include "M1.h"

    #define GET_FLAG_ENUMS
    #include "MasterFlags.h"
    #undef GET_FLAG_ENUMS

    int M1_Func(void)
    {
    return M3_Flag_Red; // Can see the enum from M3 :)
    }

    //---------- END ----------

    //---------- M1.h ----------
    #ifdef GET_FLAG_ENUMS
    M1_Flag_This,
    M1_Flag_That,
    M1_Flag_TheOther,
    #else

    #ifndef M1H
    #define M1H

    int M1_Func(void); // Prototype

    #endif // M1H
    #endif // !GET_FLAG_ENUMS
    //---------- END ----------

    //---------- M2.h ----------
    #ifdef GET_FLAG_ENUMS
    M2_Flag_Quick,
    M2_Flag_Brown,
    M2_Flag_Fox,
    #else

    #ifndef M2H
    #define M2H

    // Stuff

    #endif // M2H
    #endif // !GET_FLAG_ENUMS
    //---------- END ----------

    //---------- M3.h ----------
    #ifdef GET_FLAG_ENUMS
    M3_Flag_Red,
    M3_Flag_Green,
    M3_Flag_Blue,
    #else

    #ifndef M3H
    #define M3H

    // Stuff

    #endif // M3H
    #endif // !GET_FLAG_ENUMS
    //---------- END ----------

    The following results are printed as expected:

    9 Flags Defined
    0, 1, 2, 3, 4, 5, 6, 7, 8,
    i = 6

    Regards
    Cliff
    , May 9, 2006
    #10
    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. =?utf-8?b?QXNiasO4cm4gU8OmYsO4?=

    Enums without identifier, enums and typedef

    =?utf-8?b?QXNiasO4cm4gU8OmYsO4?=, Jan 19, 2007, in forum: C Programming
    Replies:
    10
    Views:
    1,090
    Keith Thompson
    Jan 20, 2007
  2. Replies:
    3
    Views:
    528
    Bo Persson
    Aug 15, 2007
  3. ToshiBoy
    Replies:
    6
    Views:
    825
    ToshiBoy
    Aug 12, 2008
  4. celephicus

    Macro to assign unique number to a source file

    celephicus, Jul 22, 2010, in forum: C Programming
    Replies:
    8
    Views:
    479
    Shao Miller
    Jul 28, 2010
  5. Token Type
    Replies:
    9
    Views:
    336
    Chris Angelico
    Sep 9, 2012
Loading...

Share This Page