The difference between #define and const

Hi everyone.
I'm wondering what is the differences between

#define RedLed 4

and

const int RedLed = 4;

thank you in advance.

One defines an integer whose value can not change.

The other defines a symbol substitution operation that the pre-compiler will perform, prior to the compiler being invoked.

In general, they can be used interchangeably. There are subtle differences, but in 99.9% of sketches, the differences do not matter.

MartinGS:
Hi everyone.
I'm wondering what is the differences between

#define RedLed 4

and

const int RedLed = 4;

thank you in advance.

With the define, before your program is compiled into machine runnable form, all instances of "RedLed" in your text are replaced with the text "4".

With the const int you are saying "I have an object, which is an integer, and which cannot be changed, and its value is 4"

In many cases the result is the same, but define can be used to create "macros" and more complicated doodahs. Usually when you use a define the name you give it is in upper case, which makes it easier to recognise as a define inside your sources:

#define REDLED 4
...
if (led == REDLED) {...

In your case the more modern way would be to use the const int. I think define was used a lot in the past because ints could not be forced to be constant (in older compilers).

So in your case I would use const int. In fact, though many would disagree, I'd write:

const int ikRedLed = 4 ;

which tells me that I have an integer konstant (ik).

Thanks Paul, thanks ofransen.
So, if we could just automatically replace a word like ikRedLed with a value, then why would we use const int ikRedLed = 4?
#define is shorter to write.
And when you say const int is the modern way, then i suppose there must be something more beneficial using const int?

If I understand it correctly...

constant int TheValueOne=1;

will take up memory

#define TheValueOne 1

doesn't take up any space

so I guess it saves a byte or two

can't work out why "constant int" is "more modern" though?

can't work out why "constant int" is "more modern" though?

Because it supports type-checking, which a macro doesn't.

AWOL:

can't work out why "constant int" is "more modern" though?

Because it supports type-checking, which a macro doesn't.

aha (light comes on)
cheers!

aha! so that's the difference.

AWOL:
Because it supports type-checking, which a macro doesn't.

A macro in its simplest form is just a mechanism for text substitution, but this should not prevent you from generating type qualified code.

#define RedLed (int)4
#define RedLed ((int)4)

:wink:

#define RedLed ((int)4)

ouch!!! i thought i can sum the difference already. i was wrong, they can be the same. XD
I'll just use #define when i don't need to check the type. at least its shorter to write, and seems to save memory.

Thanks guys, these enlightens.

@MartinGS: that's not exactly the same as a constant:

int const *  test = &RedLed;

If RedLed is a "const int" thist compiles. If it is ((int) 4) it won't. That is with the macro approach you get type checking and do not allocate memory. With a const you can reference but you pay allocating memory.

mmcp42:
If I understand it correctly...

constant int TheValueOne=1;

will take up memory

#define TheValueOne 1

doesn't take up any space

so I guess it saves a byte or two

can't work out why "constant int" is "more modern" though?

That is not true, and depending on the compiler a define may take up more memory than a const. The thing is that the define sort of creates a copy (maybe several copies if you use it a lot) of the value, whereas the const int is a single object. Think about it, where is the 4 stored? It must be in the memory somewhere.

I'm no Arduino compiler expert, but it could be that #define is faster when it comes to execution.

MartinGS:
Thanks Paul, thanks ofransen.
So, if we could just automatically replace a word like ikRedLed with a value, then why would we use const int ikRedLed = 4?
#define is shorter to write.
And when you say const int is the modern way, then i suppose there must be something more beneficial using const int?

int is a single object, hence in some circs better to use than storing the same value allover the place in your program.

So given that int is sometimes better than #define, why use const? Because we are fallible programmers.

// at the start of the program you may have..
int RedLed =4 ; // This should never change
int RedLedLevel = 22 ; // Brightess of the led which can change

...while programming late Friday night after too much cider I do this:

// Increase brightness...
RedLed = RedLed + 10 ;

Spot the drunken error? Now if you do this:

// at the start of the program you may have..
const int RedLed =4 ; // This should never change
int RedLedLevel = 22 ; // Brightess of the led which can change

...while programming late Friday night after too much cider I do this:

// Increase brightness...
RedLed = RedLed + 10 ;

(note the const) the compiler will complain and fail when you try to change the value of RedLed. If you know something should remain constant, and you know that you make mistakes sometimes, then make it a const object. It is a bit more typing, but it has saved my bacon in the past!

The error message you'll get will be something like:

Serial_Test:18: error: assignment of read-only variable 'RedLed'

Think about it, where is the 4 stored?

Usually as an immediate constant as part of the instruction that references it.

ofransen:

mmcp42:
If I understand it correctly...

constant int TheValueOne=1;

will take up memory

#define TheValueOne 1

doesn't take up any space

so I guess it saves a byte or two

can't work out why "constant int" is "more modern" though?

That is not true, and depending on the compiler a define may take up more memory than a const. The thing is that the define sort of creates a copy (maybe several copies if you use it a lot) of the value, whereas the const int is a single object. Think about it, where is the 4 stored? It must be in the memory somewhere.

I'm no Arduino compiler expert, but it could be that #define is faster when it comes to execution.

I modify my assertion then

constant int MyValue=42;

will create an integer that takes up memory
subsequent references to MyValue will generate an address reference

#define MyValue 42

takes up no memory at definition time
subsequent use of MyValue will generate a literal appropriate to the operation

the question is - is the address reference to an integer bigger or smaller than the literal?
either way the constant int will take up space

interesting discussion though!

AWOL:

Think about it, where is the 4 stored?

Usually as an immediate constant as part of the instruction that references it.

I have no idea about ATMEGA assembly, is that more efficient spacewise than loading from ROM?

Ah! Another point! Does const int const put into ROM or initialised in RAM at startup?

But this all probably not interesting to the original poster...!

Since I am arriving at the party a little late, I won't bother responding to previous guesses (erroneous or not). I'll just reply to the most recent post.

ofransen:
Does const int const put into ROM or initialised in RAM at startup?

It's in the instruction itself, not in a separate variable space in memory anywhere.

Here's the thing:

For programs compiled with avr-gcc optimized for space (which is what Arduino does), values of variables designated "const" are put directly into the code. So it costs nothing at run-time to use the const... thingie. (Note that this action is not part of any C or C++ language standard, and it is not absolutely, positively, unequivocally guaranteed that this will be the case with all compilers or even all versions of avr-gcc, but it is my observation using avr-gcc version 4.3.4 with arduino-0022 on my Linux system.)

Anyhow, for purposes of illustration (and confirmation of my observation), let's take the world-famous Arduino "Blink" sketch.

Compile using 13 everywhere the LED pin is referred to. (That's the way it is in my version of arduino-0022/examples/1.Basics/Blink.pde)

Then use #define ledPin 13 at the top of the sketch and change all occurrences of "13" to "ledPin" and compile again.

Of course you will get the exact same code, right? I mean, that's what #define is all about, right? (Don't take my word for it---try it.)

Now use const int ledPin = 13; instead of the #define. Compile again. I get the same code. Exactly the same. Therefore I conclude that there is no "penalty" for using the more robust construct for this example with this compiler and this version of Arduino. (See Footnote.)

Now, as has been mentioned, in general, using a "const variable" instead of #define can give the compiler some additional error checking capabilities, since type checking can be performed on usage of the "const variable" This can be a Very Good Thing since it can help the compiler find some of our usage errors.

The main other difference (to me) is that the variables designated "const..." appear to the compiler to be just like variables (except, of course, the user program won't be allowed to change the value at run time).

That means, for example, if you have a function that takes a pointer as an argument, you can send it the address of the "const variable," but you would not be able to do this with a #defined identifier.

// To see the difference between a "constant variable" declaration and
// a #define, comment out the next line and uncomment the one after it.
const int bar = 42;
//#define bar 42

void setup()
{
    // Whatever
}

void loop()
{
    int xyz[3] = {1, 2, 3};
    foo(&bar); // The address of the "constant variable"
    foo(xyz);  // The address of xyz[0];
    //
    //whatever else you want to do
    //
    
}

void foo(const int *x)
{
    // Do something with whatever it is that "x" is pointing to
}

Now, for programs like this last example, it's not a matter of whether there is some memory allocated (somewhere) for the "const int" identifier. (There is.) It's a matter of whether you can do the same thing with a #define statement. (You can't).

ofransen:
But this all probably not interesting to the original poster...!

Maybe this isn't such a BFD for beginners, but I think it is interesting and, maybe, even useful...

Regards,

Dave

Footnote:
When I said that I got the "exactly the same code," I don't just mean that I got the same sketch size. I examined the results of executing avr-objdump -d on the generated .elf files in the Arduino build directory. A "diff" showed no differences at all among the three cases of blink sketch that I mentioned above.

Here's the disassembled code for the loop() function for all three versions. The "ldi r24, 0x0D" instructions are the places where the compiler is using the value of ledPin.

000000ea <loop>:
  ea:	8d e0       	ldi	r24, 0x0D	; 13
  ec:	61 e0       	ldi	r22, 0x01	; 1
  ee:	0e 94 e2 00 	call	0x1c4	; 0x1c4 <digitalWrite>
  f2:	68 ee       	ldi	r22, 0xE8	; 232
  f4:	73 e0       	ldi	r23, 0x03	; 3
  f6:	80 e0       	ldi	r24, 0x00	; 0
  f8:	90 e0       	ldi	r25, 0x00	; 0
  fa:	0e 94 85 01 	call	0x30a	; 0x30a <delay>
  fe:	8d e0       	ldi	r24, 0x0D	; 13
 100:	60 e0       	ldi	r22, 0x00	; 0
 102:	0e 94 e2 00 	call	0x1c4	; 0x1c4 <digitalWrite>
 106:	68 ee       	ldi	r22, 0xE8	; 232
 108:	73 e0       	ldi	r23, 0x03	; 3
 10a:	80 e0       	ldi	r24, 0x00	; 0
 10c:	90 e0       	ldi	r25, 0x00	; 0
 10e:	0e 94 85 01 	call	0x30a	; 0x30a <delay>
 112:	08 95       	ret

I hate to repeat myself, but there is no guarantee that the resulting executable code will always be the same for the different cases. If people have different results, maybe they can share them with us. (Be sure to tell us what version of avr-gcc you are using, and what version of Arduino---I don't know for sure that they have always used the same optimization switches with the same effect that I reported here.)

With Arduino, a const int will always be optimized down to a literal, just like define. Arduino users do not have to worry about other compilers or architectures or whatever.

Generally, the compiler (which handles const int) is considered superior to the preprocessor (which handles defines). It's type safe and respects scope. Among C++ developers I know, its non controversial to avoid the pre processor. But frankly for most Arduino use, its an esoteric difference.

It would be kind of a programming puzzle to construct a bug that one could introduce by using define instead of const in regular usage.

a const int will always be optimized down to a literal

Sometimes two!