Can you make an incrementing compiler constant?
Asked Answered
c
S

10

17

While sounding nonsensical.....

I want a Constant where every time you use it it will increment by 1

int x;
int y;
x = INCREMENTING_CONSTANT;
y = INCREMENTING_CONSTANT;

where x == 1; and y == 2

Note I don't want y = INCREMENTING_CONSTANT+1 type solutions.

Basically I want to use it as a compile time unique ID ( generally it wouldn't be used in code like the example but inside another macro)

Sinker answered 31/3, 2010 at 22:44 Comment(5)
Since the variable is compiler based, we need to know which compiler you are talking about.Depredate
cross compiler... ideally as it will be used on at least 3 compilers.Sinker
this actually duplicates https://mcmap.net/q/745465/-incremented-define but the solutions are for C++, but will see if I the same techniques can be used for CSinker
Macro increase value and then concatenatePeltry
@LưuVĩnhPhúc that's for C++ and if you check this answer there is a solution for doing what they want in C++Sinker
A
11

If you just need something unique ID ish, can you use the __LINE__ preprocessor symbol? It's not what you're asking for, but it might work for your purposes.

Adela answered 31/3, 2010 at 22:56 Comment(2)
Agree, I always use 'LINE' for same kinds of things I see 'COUNTER' used.Pretorius
LINE Is what I want to move away from usingSinker
D
11

It's not standard, but some compilers support the __COUNTER__ macro. See Has anyone ever had a use for the __COUNTER__ pre-processor macro?

Dreamworld answered 31/3, 2010 at 22:57 Comment(0)
C
10

You may be able to put something together using Boost.Preprocessor (Works with C) and BOOST_PP_COUNTER

Example given on the docs page:

#include <boost/preprocessor/slot/counter.hpp>   
BOOST_PP_COUNTER // 0

#include BOOST_PP_UPDATE_COUNTER()   
BOOST_PP_COUNTER // 1

#include BOOST_PP_UPDATE_COUNTER()  
BOOST_PP_COUNTER // 2

#include BOOST_PP_UPDATE_COUNTER()
BOOST_PP_COUNTER // 3

Translated into what you want

#include <boost/preprocessor/slot/counter.hpp> 

int x = BOOST_PP_COUNTER; // 0

#include BOOST_PP_UPDATE_COUNTER()   
int y = BOOST_PP_COUNTER;// 1

#include BOOST_PP_UPDATE_COUNTER()  
int z = BOOST_PP_COUNTER; // 2

You could also use slots (slightly more flexible at the cost of more code than the above solution):

#include <boost/preprocessor/slot/slot.hpp>

#define BOOST_PP_VALUE 0 //ensure 0 to start
#include BOOST_PP_ASSIGN_SLOT(1) 
int a = BOOST_PP_SLOT(1); //0

#define BOOST_PP_VALUE 1 + BOOST_PP_SLOT(1)
#include BOOST_PP_ASSIGN_SLOT(1) 
int b = BOOST_PP_SLOT(1); //1
Contagious answered 31/3, 2010 at 22:55 Comment(1)
Weird construct #include BOOST_PP_UPDATE_COUNTER() - do you really have to include that every time the counter should be increased? Honestly, I don't consider this a very handy way and refrain from using this solution.Disrespectable
C
3

In my case I wanted to have a system-wide unique key for each subsystem, but the selection of subsystems would depend on the person using the system. These needed to be 8-bit values because it's targeted at embedded systems.

This is what I came up with just now:

#define LAST_KEY -1

// SUB1_KEY definition
enum {
  SUB1_KEY_ORIGIN = LAST_KEY,
  SUB1_KEY,
};
#undef LAST_KEY
#define LAST_KEY SUB1_KEY

// SUB2_KEY definition
enum {
  SUB2_KEY_ORIGIN = LAST_KEY,
  SUB2_KEY,
};
#undef LAST_KEY
#define LAST_KEY SUB2_KEY

// SUB3_KEY definition
enum {
  SUB3_KEY_ORIGIN = LAST_KEY,
  SUB3_KEY,
};
#undef LAST_KEY
#define LAST_KEY SUB3_KEY

// ....

The challenge will be making sure that the include chain that brings in each of these blocks is compiled in the same order every time.

Contextual answered 11/12, 2012 at 23:20 Comment(0)
K
1

I've often wished for compile-time variables. However, the easiest thing to do would just be to define constants for each one invididually.

The answer above me's thread problem could be solved by the use of a functionoid in some global state class or a similar sort of solution if you're using C rather than C++.

You could also try using an xmacro. Create a new file, let's call it xmacro.h

INCREMENTING_CONSTANT;
#define INCREMENTING_CONSTANT INCREMENTING_CONSTANT + 1

Then, in a standard header,

#define INCREMENTING_CONSTANT 0
#define USE_INCREMENTING_CONSTANT #include "xmacro.h"

const int x = USE_INCREMENTING_CONSTANT

I haven't tested this, but xmacros have some awesome power that regular macros can't use, like defs/undefs, and my gut says it should work. The preprocessor is powerful, but rather dumb, so it could fail.

Kennethkennett answered 31/3, 2010 at 23:0 Comment(2)
This won't work - the preprocessor doesn't see directives that result from macro expansion.Liscomb
I came upon this solution independently, tried it, and it doesn't work... which is why I'm here :-)Ferrotype
L
1

Do you want x and y to be constants themselves? If so the easiest and cleanest thing to do may be to use an anonymous enumeration:

enum {
    x = 1,
    y
    /* Add new ones here. */
};

This means you need only add a new name to that list and it will be given the next integer value. This is a useful trick where you don't care what the values are (outside runtime), as long as their distinct. For instance, when assigning identifiers to controls in a GUI, you often see:

enum {
    button1_id = FIRST_USER_ID,
    button2_id,
    combo_id,
    ...
}

Some GUI frameworks provide a GetUserId() function that will generate a new one (using an internal static variable); but I think this happens at runtime. It's also a bit tedious to see so many calls to it in succession.

button1_id = GetUserId();
button2_id = GetUserId();
combo_id = GetUserId();
...
Lyonnais answered 31/3, 2010 at 23:21 Comment(3)
sadly no, I can't use the enum thing, its completely unknown how many items there may be.Sinker
I'm not sure why that's a problem. Why is it any harder to add a new item to an enumeration than it is to (say) add another line of code to initialise it to some constant, elsewhere?Lyonnais
because the macro may appear at any point in the code. Most likely it will be in the body of a function.... and another Macro would be in the body of another function etc etc, there will be an arbitrary amount of references to the macro in many different functions. Each time the macro appears I want it to increment by 1Sinker
T
0

I've seen a couple of suggestions to use an enum here but nothing posted here seems to really solve the problem that was asked. The Boost approach is pretty hacky - it uses a massive workaround to redefine a single defined value:

https://github.com/boostorg/preprocessor/tree/master/include/boost/preprocessor/slot

Here's a possible solution using enum:

#define REGISTER_EVENT_HANDLER(name)  name,

enum {
#define APP_REGISTER_HANDLERS
#include "main.h"
#undef APP_REGISTER_HANDLERS
APP_MAX_HANDLERS
};

// ...sometime later (not really relevant but might be useful for someone)...

#define IF_RUN_HANDLER(name)  if (state == name) {
#define ENDIF_RUN_HANDLER  }

#define APP_RUN_HANDLERS
#include "main.h"
#undef APP_RUN_HANDLERS

Inside "main.h":

#include "libfile1.h";
#include "libfile2.h";
#include "libfile3.h";
#include "libfile4.h";
#include "libfile5.h";
...
#include "libfileN.h";

Inside each "libfile#.h" file:

#ifdef APP_REGISTER_HANDLERS
REGISTER_EVENT_HANDLER(my_uniquely_named_event_handler)
#endif

#ifdef APP_RUN_HANDLERS
IF_RUN_HANDLER(my_uniquely_named_event_handler)
...Do something here...
ENDIF_RUN_HANDLER
#endif

As long as the enum entries are uniquely named, they will be given unique IDs, which is kind of what the OP was after. The major feature is to #define, #include, and then #undef the earlier define at the correct points in the code. The same file can be included many times, so triggering portions of the file to emit code at various points allows each file to define multiple outputs based on which #define is currently active.

Trost answered 14/11, 2022 at 4:15 Comment(0)
C
-4

Well, it's not constant then, is it? ;)

You can do this with a function:

int id() {
  static int i = 0;
  return ++i;
}

x = id();
y = id();

As shown, this is not thread-safe. To do that you would need to protect this with a mutex, or use a compiler/platform-specific atomic incrementer.

Conflux answered 31/3, 2010 at 22:49 Comment(2)
well, compile time constant :) which is where your answer totally fails! :) hence my question, how to make an incrementing compile time constant! much like ____LINE____ changes depending what line of code you are on :)Sinker
I don't think this is quite what he wants. This will generate a new value at run time each time the function is called. I think he wants the value to be calculate once at compile time, then the same value is used every time that line is run.Vella
M
-6

An "incrementing constant" is an oxymoron. You cannot do this at compile time.

Mccallion answered 31/3, 2010 at 22:53 Comment(2)
seems like one, but the "constant" part refers to being constant at compile time rather than the symbol.Sinker
Actually it is lots of constant values, each one greater than the one beforeTowrey
L
-6

Here's an ugly way to implement it.

static int _counter=0;
#define INCREMENTING_CONSTANT (_counter++)
Location answered 1/4, 2010 at 0:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.