When to use const int, int, or #define

What is the main difference between these when naming a variable? Is what I am about to say correct?

'const int' will mainly be used when needing to declare a specific value/target to a variable? Such why I would for assigning to my Arduino UNO.

'int' is manly used as a counter, but my main issue is what is the max value for this variable? I have seen -32767 to 32767 (which i thought was 'short int') and -2147483648 to 2147483648.

'#define' is used similarly to 'const int'

int is a variable. Your code can change it as it sees fit.

const int isn’t a variable, it is a constant. It’s value is set at compile time and can’t be changed.

#define is a pre-processor directive, essentially a sort of macro. Personally I would suggest beginners steer clear of it. There’s nothing you can do with #define that you can’t do by writing the code out longhand (or by using const int/long/whatever).

Avoid using #define (a text-based symbol substitution) until you understand the problems that can arise when using it.

I use const int to define an integer variable that is not allowed to change. It can catch some types of programming errors or typos.

The maximum positive value of an "int" depends on the compiler. Most often, an int is two bytes (32767 max) or four bytes (>2 billion max). BE SURE to check when moving between target machines and compilers.

jremington:
The maximum positive value of an "int" depends on the compiler. Most often, an int is two bytes (32767 max) or four bytes (>2 billion max). BE SURE to check when moving between target machines and compilers.

So would i use 'long int' to increase the 'int' value? I am having issues with my int reaching the max value of 32767 and am looking for an alternative.

you might be interested in looking at stdint.h under Arduino/hardware/tools/avr/avr/include

pcbbc:
#define is a pre-processor directive, essentially a sort of macro. Personally I would suggest beginners steer clear of it. There’s nothing you can do with #define that you can’t do by writing the code out longhand (or by using const int/long/whatever).

That last sentence is not accurate.
There are many things you can do with macros that cannot be done with variables or writing out code longhand as macros are text substitution done on the source code before the compile is run.
One thing is that you test for the symbols existence during compilation if it created with a #define using conditionals
Macros can get very sophisticated especially if using some of the more advanced pre-processor capabilities like concatenation or pasting.
If you roll the clock back say 30 years, things like const types and inline functions didn't exist so the use of macros was actually necessary.

But today and especially for something like a simple value, a const int would generally be preferred over a #define as it can be safer to avoid #define so you can avoid some silent issues.

For example:
On the AVR if you need a value that is larger than a 16 bit int, it is much safer to use a const variable like this:

const uint32_t var = 100000;

This will give you the desired value for var

Since if you do this:

#define var 80000

This will not work as expected on the AVR as it will be truncated to an int which would change the 80000 to 14464 due to only using the lower 16 bits as it converted the value to an int which is only 16 bits on the AVR
i.e. you end up with var being 14464 instead of 80000

You would need to do this:

#define var 80000L

This ensures that the value is not truncated to 16 bits

It is easy to accidentally forget to declare the constant as "long".

There are more complex cases where it isn't as obvious that you end up with a truncated value when using a #define

--- bill

Using #define for compile time constants is a hold-over from the C programming language. It can be used in C++, but there are better ways.

'const int' (and it's relatives) have some uses, but there are subtle pitfalls with them. For example, in many cases the compiler is required to allocate storage for these values, even though they never change! This is obviously different from a '#define', which is straight textual substitution. Most importantly, they can't be used in very common situations where #define DOES work, for example as the size of an array.

The new way of doing things for C++ is a relatively new mechanism call 'constexpr'.

You would use 'constexpr' like you would use 'const', except that this tells the compiler that the value MUST be known to the compiler at compile time. In this way it acts like a '#define' - since the value is known to the compiler, no storage need be allocated for it.

//  Old way, the way most people know about
#define LEGNTH_OF_DAY 84600

//  OOOPS, if you use it in an integer context, you get warnings where you use it, not where it's defined!
int x = LENGTH_OF_DAY;   //  BAD BAD BAD, on AVR ints are 16 bits.

//  A bad compromise - don't do this
const int COUNT_OF_THINGS = 5;

//  It doesn't work well, because you can't use it in many situations where the compiler wants a 'real' constant.
bool doIHaveTheThing[COUNT_OF_THINGS] = {false, false, false, false, false];  // Doesn't compile!


//  THE NEW HOTNESS - constexpr

constexpr int COUNT_OF_THINGS = 5;
bool doIHaveTheThing[COUNT_OF_THINGS] = {false, false, false, false, false];   // YAY! it works!

constexpr int LENGTH_OF_DAY = 84600;  ///  WARNING happens here because ints are 16 bits.
constexpr unsigned long SECONDS_PER_DAY = 84600L; //  OK

More reading:

@bperrybap
@MHotchin
Yes, I’m aware of how to use #define properly and that what I wrote was an over simplification.

But in regard to the OPs question...

What is the main difference between these when naming a variable?
....
'#define' is used similarly to 'const int'

...and their level of experience I stand by my statement and judgement that they do not need to be confused by a full explanation at this point. Hence it’s much better they steer clear of #define.

When novices try to use #define we end up with code like...

 #define LEGNTH_OF_DAY 84600;
#define LEGNTH_OF_DAY = 84600

LEGNTH_OF_DAY = LEGNTH_OF_DAY * 2;

...and many other heinous misunderstandings of what they are doing.

pcbbc:
But in regard to the OPs question......and their level of experience I stand by my statement and judgement that they do not need to be confused by a full explanation at this point. Hence it’s much better they steer clear of #define.

I totally agree which is why I said:

If you roll the clock back say 30 years, things like const types and inline functions didn't exist so the use of macros was actually necessary.
But today and especially for something like a simple value, a const int would generally be preferred over a #define as it can be safer to avoid #define so you can avoid some silent issues.

--- bill

bperrybap:
But today and especially for something like a simple value, a const int would generally be preferred over a #define as it can be safer to avoid #define so you can avoid some silent issues.

If you are using #define for simple constants, then 'constexpr' is preferred over 'const'. 'constexpr' does the same type checking, but it can also be used as template parameters and array sizes, and it does not require storage unless you take its address.

MHotchin:

//  A bad compromise - don't do this

const int COUNT_OF_THINGS = 5;

//  It doesn't work well, because you can't use it in many situations where the compiler wants a 'real' constant.
bool doIHaveTheThing[COUNT_OF_THINGS] = {false, false, false, false, false];  // Doesn't compile!

It compiles fine for me (after correcting the ']' vs. '}' typo).

johnwasser:
It compiles fine for me (after correcting the ']' vs. '}' typo).

I am scratching my head on this as well. That's a construct I use often.

OP- If you are still with us......
Are you more or less confused now?

const int COUNT_OF_THINGS = 5;

// It doesn't work well, because you can't use it in many situations where the compiler wants a 'real' constant.
bool doIHaveTheThing[COUNT_OF_THINGS] = {false, false, false, false, false]; // Doesn't compile!

It compiles fine for me (after correcting the ']' vs. '}' typo).

Depends on the compiler, GCC seems to be happy with it, XC32 (PIC) is not. XC32 sees it as a variable that does not change, but as variables can change, even if they can't, they are no good as used above.

johnwasser:
It compiles fine for me (after correcting the ']' vs. '}' typo).

Ahh, my mistake. In this case, it works, since both the declaration and definition are visible.

But, if your 'const int' is declared but not defined, it doesn't. 'constexpr' is always defined at declaration, so if the name is visible it is usable.

External linkage and function parameters come to mind.