Go Down

Topic: #define vs. const (Read 775 times) previous topic - next topic

Ken_F

Hi all,
Could someone tell me what difference(s) there are when using #define vs. const to setup a reoccurring pin definition?  I want to identify pin 2 with the name "Blank".  Is one better than the other? (faster, uses less memory. etc)

ie.:
#define Blank 2
vs.
const Blank 2

UKHeliBob

The first thing to note is that
Code: [Select]
const Blank 2
is not valid code, which I assume you realise
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

MorganS

#2
Mar 22, 2019, 02:47 pm Last Edit: Mar 22, 2019, 02:48 pm by MorganS
#define is like replacing the text. It gives the exact same result as a search-replace. So you can get unexpected results....

Code: [Select]
#define THREE 1 + 2

  Serial.println( 2*THREE );
  Serial.println( 2*1 + 2 );


Can you see why both println statements will print "4" and not "6"?

You can use this to your advantage. The Arduino #define ISR does some clever text manipulation so that you use it like a function even though it is not a function.

The advantage of the const declaration is the compiler can check the type of the variable. (Which you forgot.)

In your simple example, the compiler will optimize the result down to the same machine code. Even if you didn't use the const keyword, it works out that it is a constant. The const declaration is more for your benefit, so you don't accidentally change it.
"The problem is in the code you didn't post."

GypsumFantastic

I always prefer const because it's C and I know how to do C (mostly).

#define uses the preprocessor which has its own set of rules and syntax, and I've never really spent much time learning preprocessor. Also it seems like it can sometimes throw you a curve-ball (as in MorganS's example above) if you don't pay attention. I know preprocessor is essential for other things, but for defining constants why even go there?

boolrules

This hardly demonstrates a problem with the preprocessor.

#define is like replacing the text. It gives the exact same result as a search-replace. So you can get unexpected results....

Code: [Select]
#define THREE 1 + 2

  Serial.println( 2*THREE );
  Serial.println( 2*1 + 2 );


Can you see why both println statements will print "4" and not "6"?
If you understand why the 2nd println fails, you know why the 1st also failed. You shouldn't expect otherwise.

Code: [Select]

#define THREE (1 + 2)    // the way you should write such an expression anywhere (if that IS what you mean)
#define THREE    3       // the obvious way

Danois90

#5
Mar 22, 2019, 03:54 pm Last Edit: Mar 22, 2019, 07:06 pm by Danois90
Defines can be "dangerous" if carelessly used, unless you are absolutely sure what you are doing, you should use const instead. Defines can be "overwritten" causing a define to change its value, const declarations will not allow this and therefore they are safer to use.

And for the memory usage: Same, same - either it fits or it doesn't! ;)
Instead of mocking what's wrong, teach what's right! ;)
When you get help, remember to thank the helper and give some karma!
Please, do NOT send me any private messages!!

MorganS

For trivial examples, pin numbers and whatever, the const is usually better. But #define is better used for calculation, where it looks more like a function.

In those cases, it is usually better to use an actual function, maybe with the inline compiler hint to encourage it to make the program faster by making it bigger.

Like any good tool, it can be used for many purposes, including hammering your own thumb.
"The problem is in the code you didn't post."

Ken_F

Sorry UKHeliBob, I should have written const Blank = 2;
I was in a bit of a rush.

gfvalvo

Try again:
Code: [Select]
const uint8_t Blank = 2;
No technical questions via PM. They will be ignored. Post your questions in the forum so that all may learn.

Ken_F

Thanks for the reply gfvalvo, I think, but posting just a line of code with no explanation just leaves me in the dark.  How about so incite into what you are trying to tell me please?

MorganS, I understand why the second println returned 4 but I'm unclear on the value of "#define THREE 1 + 2".
Also why did say  I forgot the compiler can check the type of the variable?
"The advantage of the const declaration is the compiler can check the type of the variable. (Which you forgot.)"

gfvalvo

How about so incite into what you are trying to tell me please?
You need to supply a TYPE for the variable, not just a name and a value -- i.e. 'int', 'unsigned long', 'uint32_t', 'float', 'double', 'in16_t', etc, etc, etc.
No technical questions via PM. They will be ignored. Post your questions in the forum so that all may learn.

Ken_F

Thanks gfvalvo, I don't know where my head was at when I typed that, but I do know that.  The initial example was just fyi and not of crucial importance to the general question.

So the bottom line as I see it is use "const" instead of "#define" to prevent the names from changing value.

J-M-L

kind-of... bottom line is that they are two different things :) and #define somewhat something of the past for constants (due to inline and compiler optimization techniques);

# directives are better suited for pre-processor stuff

Strongly typing variables and constants helps provide cues to the compiler which can warn you if you do something stupid later on - including changing values or overflow in maths etc

Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

Ken_F

Thanks J-M-L, but you're talking over my head with,

# directives are better suited for pre-processor stuff

Strongly typing variables and constants helps provide cues to the compiler which can warn you if you do something stupid later on - including changing values or overflow in maths etc

I have no idea what #directives, or pre-processor stuff is or what you mean by "Strongly typing"

Danois90

#14
Mar 22, 2019, 08:06 pm Last Edit: Mar 22, 2019, 08:19 pm by Danois90
The pre-processor is what makes the source code ready for compiling. Strongly typing means that you, as the programmer, instruct the compiler to use exactly the data types you want. Look at the following snippet:

Code: [Select]
#define PIN_NUMBER 3
...
pinMode(PIN_NUMBER, OUTPUT);
digitalWrite(PIN_NUMBER, HIGH);
digitalWrite(PIN_NUMBER, LOW);


The pre-processor will convert the code and feed the following to the compiler:

Code: [Select]
pinMode(3, OUTPUT);
digitalWrite(3, HIGH);
digitalWrite(3, LOW);


As you can see, "PIN_NUMBER" does no longer exist, only the value it defines does. Since "int" is the default data type, "3" may occupy 2 bytes in memory because it is un-typed. Now, lets try that with "strong typing":

Code: [Select]
const uint8_t PIN_NUMBER = 3;
...
pinMode(PIN_NUMBER, OUTPUT);
digitalWrite(PIN_NUMBER, HIGH);
digitalWrite(PIN_NUMBER, LOW);


In this example the pre-processor will not modify anything. "PIN_NUMBER" will exist at compile time and it will occupy exactely one unsigned byte - because you coded it like that.
Instead of mocking what's wrong, teach what's right! ;)
When you get help, remember to thank the helper and give some karma!
Please, do NOT send me any private messages!!

Go Up