Macro to assign unique number to a source file

C

celephicus

Greetings

I use a macro below to get a guaranteed unique number to identify
source files for asserts in a system with very little memory. This
works fine, but sometimes braindead compilers do not optimise away the
dummy function, so it appears in the object file. Is there another way
of checking for no duplicates in "C"?

#define FILENUM(n) \
void errorHandlerDummyFunctionForCheckingFileNumber_##n(void) {} \
enum { F_NUM = (n) }

TomH
 
T

Thad Smith

celephicus said:
I use a macro below to get a guaranteed unique number to identify
source files for asserts in a system with very little memory. This
works fine, but sometimes braindead compilers do not optimise away the
dummy function, so it appears in the object file. Is there another way
of checking for no duplicates in "C"?

#define FILENUM(n) \
void errorHandlerDummyFunctionForCheckingFileNumber_##n(void) {} \
enum { F_NUM = (n) }

I would create a separate header file
filenums.h:
enum {
FILEA=1,
FILEB=2,
FILEC=3};

In file filea.c:
#include "filenums.h"
#define F_NUM FILEA

Keep the entries in filenums.h in numeric order, which allows you to easily
verify uniqueness manually. You could, of course, omit the explicit enum
assignment, but then the numeric value isn't obvious. You could also write a
utility to verify uniqueness and run it as part of the build process.
 
I

Ian Collins

Greetings

I use a macro below to get a guaranteed unique number to identify
source files for asserts in a system with very little memory. This
works fine, but sometimes braindead compilers do not optimise away the
dummy function, so it appears in the object file. Is there another way
of checking for no duplicates in "C"?

One bodge I have used on small system is to log the PC and determine the
function form the map file..
 
C

celephicus

I would create a separate header file
filenums.h:
enum {
   FILEA=1,
   FILEB=2,
   FILEC=3};

In file filea.c:
#include "filenums.h"
#define F_NUM FILEA

Good idea, because the information is defined in exactly one place,
not spread over all source files. Plus I can easily find the relevant
file relating to a filenumber from one source file, previously I was
using "grep FILENUM *.c". And any decent scripting language can
autogenerate the enum in about 3 lines.

TomH
 
E

Eric Sosman

Greetings

I use a macro below to get a guaranteed unique number to identify
source files for asserts in a system with very little memory. This
works fine, but sometimes braindead compilers do not optimise away the
dummy function, so it appears in the object file. Is there another way
of checking for no duplicates in "C"?

#define FILENUM(n) \
void errorHandlerDummyFunctionForCheckingFileNumber_##n(void) {} \
enum { F_NUM = (n) }

The errorHandler... thing is to help you detect accidental re-use
of identical `n' values in different files, is that it? Then if the
compiler were to remove the function, what would happen to your error
detection?

Also, calling a compiler "braindead" because it compiles a function
you told it to compiler seems a little harsh. Seems to me the smell of
cranial necrosis arises from a different source entirely ...
 
S

Shao Miller

I don't know if you might be interested in counting in headers or not,
but:
-----
/* foo.h */
#define MAGIC_COUNT_NEXT foo
#include "magic_count.h"
#define MAGIC_COUNT_CUR foo

/* ... */

/* End of foo.h */
-----
/* bar.h */
#define MAGIC_COUNT_NEXT bar
#include "magic_count.h"
#define MAGIC_COUNT_CUR bar

/* ... */

/* End of bar.h */
-----
/* baz.h */
#define MAGIC_COUNT_NEXT baz
#include "magic_count.h"
#define MAGIC_COUNT_CUR baz

/* ... */

/* End of baz.h */
-----
#ifdef MAGIC_COUNT_USAGE
/*
* magic_count.h (C) 2010 Shao Miller
* Use and adaptation permitted, if credit for origin is included.
*
* Usage:
*
* #define MAGIC_COUNT_NEXT foo
* #include "magic_count.h"
* #define MAGIC_COUNT_CUR foo
*
* Then MAGIC_COUNT will be #defined to a size_t
* integer constant expression
*/
#endif

#ifndef MAGIC_COUNT_CUR
#ifdef MAGIC_COUNT
#error "You forgot to #define MAGIC_COUNT_CUR after #including"
#else
#define MAGIC_COUNT 0
#endif
#define MAGIC_COUNT_FIRST 1
#define MAGIC_COUNT_PASTE2(x,y) x ## y
#define MAGIC_COUNT_PASTE(x,y) MAGIC_COUNT_PASTE2(x,y)
#endif

#ifndef MAGIC_COUNT_NEXT
#error "You forgot to #define MAGIC_COUNT_NEXT before #inlcuding"
#endif

#ifdef MAGIC_COUNT_INC
#error "You already have MAGIC_COUNT_INC #defined"
#endif

#define MAGIC_COUNT_INC() \
\
struct MAGIC_COUNT_PASTE(MAGIC_COUNT_S_, MAGIC_COUNT_NEXT) {\
char (*count)[MAGIC_COUNT + 1]; }

MAGIC_COUNT_INC();

#if MAGIC_COUNT_FIRST
#undef MAGIC_COUNT
#define MAGIC_COUNT \
\
(sizeof \
*(((struct MAGIC_COUNT_PASTE(MAGIC_COUNT_S_,MAGIC_COUNT_CUR) *)0)-
)
#undef MAGIC_COUNT_FIRST
#endif

#undef MAGIC_COUNT_INC
#undef MAGIC_COUNT_NEXT
#ifdef MAGIC_COUNT_CUR
#undef MAGIC_COUNT_CUR
#endif
/* End of magic_count.h */
-----
/* main.c */
#include "foo.h"
#include "bar.h"
#include "baz.h"

int main(void) {
return (int)MAGIC_COUNT;
}

/* End of main.c */
 
S

Shao Miller

Probably won't be submitting that for any obfuscated code contests, so
'typedef'fing a simple 'char[XXX]' type and taking its 'sizeof' would
be less challenging to read than the fun 'struct' business. Heheh.
 
P

Peter Nilsson

Not the usual assert() macro then?! Do you really need a
number? What do you do with it? What's wrong with __FILE__?

Well, if you're braindead enough to put in the dummy function... ;)
I would create a separate header file
filenums.h:
enum {
   FILEA=1,
   FILEB=2,
   FILEC=3};

In file filea.c:
#include "filenums.h"
#define F_NUM FILEA

Keep the entries in filenums.h in numeric order, which
allows you to easily verify uniqueness manually. You
could, of course, omit the explicit enum assignment, but
then the numeric value isn't obvious.  You could also
write a utility to verify uniqueness and run it as part
of the build process.

Built in uniqueness...

/* begin header */

#define FILE_NAMES(M,_) \
M( FILE_A, "FileA.c" ) _ \
M( FILE_B, "FileB.c" ) _ \
M( FILE_C, "FileC.c" ) _ \
M( FILE_D, "FileD.c" )

#define COMMA ,
#define SEMI_COLON ;
#define AS_ENUM(a,b) a

enum { FILE_NULL=0, FILE_NAMES(AS_ENUM, COMMA) };

/* end header */

#include <stdio.h>
/* include above header in required files */

#define AS_PRINTF(a,b) printf("%s,%d,\"%s\"\n", #a, a, b)

int main(void)
{
FILE_NAMES(AS_PRINTF, SEMI_COLON);
return 0;
}

Assigned values validator...

/* begin header */

#define FILE_NAMES(M,_) \
M( FILE_A, 1, "FileA.c" ) _ \
M( FILE_B, 2, "FileB.c" ) _ \
M( FILE_C, 3, "FileC.c" ) _ \
M( FILE_D, 2, "FileD.c" )

#define COMMA ,
#define SEMI_COLON ;
#define AS_ENUM(a,b,c) a = b

enum { FILE_NULL=0, FILE_NAMES(AS_ENUM, COMMA) };

/* end header */

#include <stdio.h>
/* include above header in required files */

#define AS_ARRAY(a,b,c) { #a, a }

struct {
const char *enum_name;
int value;
} array[] = { FILE_NAMES(AS_ARRAY, COMMA) };

#define countof(x) (sizeof(x) / sizeof*(x))

int main(void)
{
int okay = 1;
size_t i, j;

for (i = 0; i < countof(array) - 1; i++)
for (j = i + 1; j < countof(array); j++)
if (array.value == array[j].value)
{
printf("%s and %s both have value %d\n",
array.enum_name,
array[j].enum_name,
array.value);
okay = 0;
}

if (okay) puts("okay!");

return 0;
}
 
S

Shao Miller

Probably won't be submitting that for any obfuscated code contests, so
'typedef'fing a simple 'char[XXX]' type and taking its 'sizeof' would
be less challenging to read than the fun 'struct' business.  Heheh.

Or adding to an 'enum' might be even simpler than even that.
 

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,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top