Globally unique enums or macro values?

U

userblue

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
 
I

Ian Collins

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;
};
 
U

userblue

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
 
K

Keith Thompson

Ian Collins said:
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.)
 
U

userblue

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 :-(
 
I

Ian Collins

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!
 
R

Rod Pemberton

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
 
T

Thad Smith

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.
 
U

userblue

Thad, thanks for the suggestion, it looks interresting. I'll
investigate and let you know how I get on.
 
U

userblue

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top