1

I'm using a preprocessor #define macro to count the number of functions in a header file:

#define __INDEX -1

//First group of functions
void func1(void);
#define __FUNC1_INDEX __INDEX + 1
void func2(void);
#define __FUNC2_INDEX __FUNC1_INDEX + 1
#undef __INDEX
#define __INDEX __FUNC2_INDEX

//Second group of functions
void func3(void);
#define __FUNC3_INDEX __INDEX + 1
void func4(void);
#define __FUNC4_INDEX __FUNC3_INDEX + 1
#undef __INDEX
#define __INDEX __FUNC4_INDEX

//Third group of functions
void func5(void);
#define __FUNC5_INDEX __INDEX + 1
void func6(void);
#define __FUNC6_INDEX __FUNC5_INDEX + 1
#undef __INDEX
#define __INDEX __FUNC6_INDEX

#define __NUM_FUNCTIONS __INDEX + 1

The preprocessor gets through the first two sets of functions just fine, but when it reaches the line:

#define __FUNC5_INDEX __INDEX + 1

I get a "not defined in this scope" error for __INDEX. What makes this really confusing is the fact that the same exact thing is done [successfully] in the second group of functions; __FUNC3_INDEX takes on the value of __INDEX + 1. There's no typos anywhere, as far as I can tell... what's the problem?

I'm using g++ 4.8.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
NmdMystery
  • 2,778
  • 3
  • 32
  • 60
  • Those are [reserved identifiers](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier). – chris Oct 24 '13 at 03:52
  • Ah, I see. I used the double underscore as a way of hiding symbols I only needed to use once. – NmdMystery Oct 24 '13 at 03:55
  • I notice that I don't have this problem with other macros of mine with double underscores, should I stop doing that anyway? – NmdMystery Oct 24 '13 at 03:57
  • Hmm... I tested my code there too and it worked fine. Compiler bug? – NmdMystery Oct 24 '13 at 04:05
  • The error is happening when you try to use `__INDEX`. This is an important piece you left out of your question. – jxh Oct 24 '13 at 04:14
  • Although it is not the source of your trouble, names starting with either two underscores or with an underscore and an upper case letter are reserved for use by the implementation for any purpose. Names starting with a single underscore are also reserved for use by the implementation, so basically, avoid starting names with underscores unless you're writing "part of the implementation". You'll know if you're writing "part of the implementation"; most people are not. C++ additionally reserves double underscores appearing anywhere in a name for the implementation. Don't use a double underscore! – Jonathan Leffler Oct 24 '13 at 06:05

1 Answers1

2

You can't count with preprocessor macros. They are just string expansions.

After the preprocessor finishes with this:

#define __FUNC5_INDEX __INDEX + 1
#define __FUNC6_INDEX __FUNC5_INDEX + 1
#undef __INDEX
#define __INDEX __FUNC6_INDEX

The following definitions are in effect:

__FUNC5_INDEX → __INDEX + 1
__FUNC6_INDEX → __FUNC5_INDEX + 1
__INDEX → __FUNC6_INDEX

No computation has been done. What's more, no replacement is performed inside a #define directive.

Now, when you attempt to expand __INDEX (possibly as part of an expansion of __NUM_FUNCTIONS, the following will happen:

__INDEX → __FUNC6_INDEX
        → __FUNC5_INDEX + 1
        → __INDEX + 1 + 1

At this point, the macro expansion stops because you cannot expand a macro inside of its own expansion. The token is just left as-is.

Consequently, you'll end up using the symbol __INDEX inside the program, as a variable. But since the variable __INDEX has never been defined, you get an error.

By the way, don't use symbols starting with two underscores, or with one underscore and a capital letter. Those are reserved for the standard library.

rici
  • 234,347
  • 28
  • 237
  • 341
  • 1
    So it's impossible to do what I'm trying to do? – NmdMystery Oct 24 '13 at 04:07
  • 1
    @NmdMystery: Just about. Sorry. – rici Oct 24 '13 at 04:08
  • But is there a reason it compiles without error on Ideone, as jxh pointed out? I would see if this is true for Visual Studio as well but I'm on Linux. I also swear I've seen various libraries do the double underscore thing. – NmdMystery Oct 24 '13 at 04:11
  • @NmdMystery The first link in jxh's comment shows a compiler error. In the second one (C++), __NUM_FUNCTIONS is never used, so there is no error. The error has nothing to do with the double underscore. – rici Oct 24 '13 at 04:13
  • I guess I'll just have to count it manually for the time being, then. – NmdMystery Oct 24 '13 at 04:18