I found this in an example sketch when defining motor pins and encoder pins as global variables for Arduino UNO R3. So, these assigned values should never change. But i am wondering what's the difference in the way they are defined and if i should prefer one way of defining these global variables over the other? Which is better and why? And are there other ways of defining a variable which holds a pin value that should never change?
const int left_L2=6;
const int PWM_L=9;
#define PinA_left 2
#define PinA_right 3
#define instructs the pre-processor to substitute '2' where ever it sees "PinA_left". That's it. When you use "const int left_L2" the compiler assigns two bytes of RAM and puts the value 0x0006 there. Whenever you reference "left_L2" that address is referenced as an integer.
#define can, in some cases, reduce code size and speed execution.
But because it's just a copy-paste, you need to be careful of its use, especially when the define is something where, say, a calculation or other similar operation is done and/or it's multiple lines. For example, if you have a macro that spans multiple lines of code, or interacts with other code, you need to be very judicious about the use of parenthesis to ensure the resultant expression structure after substitution is as expected.
Gurus and CPPClerics here will likely decry the macro as somehow non-canonical. Done carefully, I think they're fine, especially in the usage you're describing.
Blackfin:
When you use "const int left_L2" the compiler assigns two bytes of RAM and puts the value 0x0006 there. Whenever you reference "left_L2" that address is referenced as an integer.
Often the compiler will determine that there is no need to assign any RAM for the constant, and instead substitutes the constant value directly into the code in a similar fashion to the #define. One distinct difference is with the const there is also a declaration of type (int in this case), so the compiler checks for correct type with each use.
Instead of 'const int foo=2', you can use 'constexpr int foo = 2'. This is a strong hint to the compiler that storage for the value is not needed - the value is guaranteed to be available at compile time. You can also use a 'constexpr' in places where 'const int' sometimes wouldn't work, like template parameters and array sizes.
#define is an older method. Like 1960's old. It is still useful, but for simply creating constant values like pin numbers or calibration constants, it's better to use the newer methods.
Thanks everyone for the feedback. I guess, it's preferable to use '#define' for all pin definitions instead of 'const int', since the reason is that it will save memory, which is very precious with the limited 2 Kb of the Arduino UNO R3.
MorganS: #define is an older method. Like 1960's old. It is still useful, but for simply creating constant values like pin numbers or calibration constants, it's better to use the newer methods.
I wasn't aware that '#define' was deprecated. I'm trying to keep my code concise and up-to-date. What are the newer methods? MHotchin mentioned above using 'constexpr int foo = 2'. Is that one of the recommended or newer methods, as long as it works in Arduino IDE 1.8.10 for my Arduino UNO R3 board?
#define is a preprocessor instruction. some things can't be done without it. if you want to have a code which compiles only on some architectures, you put it in #ifdef#endif where the ifdef can't use a constant, only a #define
for all other uses use a constant for a value and inline function instead of a macro.
the rule is, use #define only for things which can't be done without it
using define for a pin number will not save any memory. the parameter is a number either way.
This comes up once in a while. Use const or constexpr. Has a lot less pitfalls, gives clear error and the compiler is in full control. Now it can determine if it's wise to put it in memory or not etc. And compiler got very good at that
That's why I think the advice of GypsumFantastic is bad. Analogy: I find it easy to just whack wires into a socket when I'm testing stuff. A newbie might also find that easy. Trouble is, I know what I'm doing (trust me, I'm an engineer ) and a newbie does not. So I would still advice to use a plug. And in most cases I would also still use a plug, comes with a lot less possible side effects
All in all, there is a od reason why they added const and constexpr to the language
DryRun:
Thanks everyone for the feedback. I guess, it's preferable to use '#define' for all pin definitions instead of 'const int', since the reason is that it will save memory, which is very precious with the limited 2 Kb of the Arduino UNO R3.
The compiler is staggeringly efficient at saving memory and processor cycles. It will do stuff that you won't even think of 10 years from now.
Try something like this...
int x = 6;
void setup() {
Serial.begin(9600);
for(int i=0; i< 32765; i++) {
}
Serial.print("Half of x is ");
Serial.print(x/2);
}
void loop(){}
Start with the for() loop. It does nothing. So the compiler removes it completely. It can also do tricks like "unrolling" a loop to make it faster.
Then we divided x by 2. Integer division is "expensive" on the Arduino. But dividing by 2 is the same as shifting the integer one bit to the right. So it will use the bitshift operator where possible.
It gets better. The compiler can see that we used x as a constant, even though we didn't explicitly say that. So it does the divide-by-2 and the code that runs on the Arduino doesn't even contain the bitshift instruction.
That means that x never gets stored in the precious SRAM memory. The value 3 is stored in the program storage area.