Different data sizes in program usage

Hutkikz:
But it has a type. so it's better than a define.

Yes, in the previous replies, I read the compiler checking for a type and I thought that would be not an advantage.
So now what is the advantage of using a type than define ?

Try:

#define BIGNUM 30000
#define LITTLENUM 10

unsigned long answer = BIGNUM * LITTLENUM;

and

const unsigned long BIGNUM=30000;
const unsigned long LITTLENUM =10;


unsigned long answer = BIGNUM * LITTLENUM;

How about this one ?

const uint8_t CS_PIN =          10;
const uint8_t MOSI_PIN =        11;
const uint8_t CLK_PIN =         13;
const uint8_t CMD_MSK =         0xF8;
const uint8_t DATA_MSK =        0xFA;
const uint8_t DISPLAY_CLEAR =   0x01;
const uint8_t RETURN_HOME =     0x02;
const uint8_t ENTERY_MODE =     0x06;
const uint8_t DISPLAY_CONTROL = 0x0C;
const uint8_t DIS_CURSOR_CTL =  0x14;

vs

enum: uint8_t{CS_PIN = 10, MOSI_PIN = 11, CLK_PIN = 13, CMD_MSK = 0xF8,
DATA_MSK = 0xFA, DISPLAY_CLEAR = 0x01, RETURN_HOME = 0x02, ENTERY_MODE = 0x06,
DISPLAY_CONTROL = 0x0C, DIS_CURSOR_CTL =  0x14};

They are the same, right ? Are there any advantages or disadvantages of using anyone ?

To me the second option saves more lines, so the header is shorted, but the first one is better for readability.

How is a display control code related to a pin number?

TheMemberFormerlyKnownAsAWOL:
How is a display control code related to a pin number?

It's not related of course, I just copied them from the header file, they are now in #define form; like this:

// pins configurations
#define CS_PIN						10
#define MOSI_PIN					11
#define CLK_PIN						13
// glcd main defs
#define CMD_MSK						0xF8
#define DATA_MSK					0xFA
// glcd basic instruction set
#define DISPLAY_CLEAR				        0x01
#define RETURN_HOME					0x02
#define ENTERY_MODE					0x06	// CURSOR_MOVE_RIGHT=1, DIS_SHIFT_R/L=0
#define DISPLAY_CONTROL				        0x0C	// DIS=ON, CURSOR=OFF, BLINK=OFF
#define DIS_CURSOR_CTL				        0x14	// cur mov right, no dis shift
#define FUNCTION_SET_BASIC			        0x30	// 8-bit, basic instruction set
#define CHAR_GEN_ADDRESS			        0x40	// ORed w A5-A0 6bit add 0x00 - 0x3f
//#define DATA_RAM					0x80	// ORed w A5-A0, A6=0, 6bit add
// glcd extended instruction set
#define FUNCTION_SET_EXTENDED		                0x34	// 8-bit, extended instruction set
#define GRAPHICS_ON1				        0x32	// graphics on
#define GRAPHICS_ON2				        0x36	// graphics on
#define GRAPHICS_OFF1				        0x34	// graphics off
#define GRAPHICS_OFF2				        0x30	// graphics off
#define STANDBY_MODE				        0x01	// put glcd in standby mode
#define DISABLE_V_SCROLL			        0x02	// disable vertical scroll => CGRAM
#define ENABLE_V_SCROLL				        0x03	// enable vertical scroll 

//////////////////////////////////////////////////////////////////////////////////
typedef enum: uint8_t  {START, CS_HI,	INIT_CMD}LCD_INIT;
typedef enum: uint8_t  {CONTROL, PIXEL_WRITE, CHARS_WRITE, IMG_DRW,
CLEAR_DISPLAY, CIRCLE_DRW, LINE_DRW, RECTANGLE_DRW}LCD_MODES;
typedef enum: uint8_t  {IDLE, CMD, DATA}LCD_CMDT;

I'm arranging them and commenting them as sections.


OK, got your point.

You mean this is better:

enum: uint8_t{CS_PIN = 10, MOSI_PIN = 11, CLK_PIN = 13};
enum: uint8_t{CMD_MSK = 0xF8, DATA_MSK = 0xFA};
enum: uint8_t{DISPLAY_CLEAR = 0x01, RETURN_HOME = 0x02, ENTERY_MODE = 0x06,
DISPLAY_CONTROL = 0x0C, DIS_CURSOR_CTL =  0x14};

countrypaul:
Try:

#define BIGNUM 30000

#define LITTLENUM 10

unsigned long answer = BIGNUM * LITTLENUM;





and




const unsigned long BIGNUM=30000;
const unsigned long LITTLENUM =10;

unsigned long answer = BIGNUM * LITTLENUM;

Tried it like this:

const unsigned long BIGNUM=30000;
const unsigned long LITTLENUM =10;
//#define BIGNUM 30000
//#define LITTLENUM 10


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  unsigned long answer = BIGNUM * LITTLENUM;
  Serial.println(answer);
}

The same result. I don't know if I tested it with the proper way or not.

What platform are you on as with a 16bit like the Uno you should get the right answer with the const version but the #define version should do the calculation at int (16 bit) and consequently lose part of the answer.

For the #define version on an UNO:

/home/pi/Arduino/forumTest/forumTest.ino:4:31: warning: integer overflow in expression [-Woverflow]
 unsigned long answer = BIGNUM * LITTLENUM;
                               ^

And the output:

4294939616

Although presumably if you realized the constants needed to be unsigned longs, the #defines would have been done properly:

#define BIGNUM 30000ul
#define LITTLENUM 10ul

If you search "define vs enum vs const" you will get tons of opinions many of which were written before constexpr and enum typing were available. I ended up using constexpr for constants that stand on there own and enum for logical states For me this seems to best satisfy questions of: Type Safety, clear and understandable programming technique and avoidance of obscure bugs like the one discussed above. YMMV

countrypaul:
What platform are you on as with a 16bit like the Uno you should get the right answer with the const version but the #define version should do the calculation at int (16 bit) and consequently lose part of the answer.

Wait, sorry I just compiled that only, I thought you mean the size of compiled program and not just at run time.
I'm using nano board and you're right, with defines it gets out of control, it gave 4294939616 !
Yep, where with const long, the answer is right 300000.

Hutkikz:
If you search "define vs enum vs const" you will get tons of opinions many of which were written before constexpr and enum typing were available. I ended up using constexpr for constants that stand on there own and enum for logical states For me this seems to best satisfy questions of: Type Safety, clear and understandable programming technique and avoidance of obscure bugs like the one discussed above. YMMV

Oh yes, I like your arrangement of logical states and const values you use constexpr.
So what I understood until now is that:

  1. constexpr could be more optimized than define
  2. sharing the properties of const and defines
    Are my conclusions right ?

The point of an enum is it creates a new type, and a variable of that type can ONLY be set to the value of one of the enums. You CANNOT do that with #defines. That, and what you just saw with the calculation example, are perfect examples of WHY type-checking is important, and why const variables and enums are better/safer to use than #defines. Arguably, at this point, #defines should be used only for macro definitions, controlling pre-processor conditionals, etc.. Even then, they must be used with great care, or you can create some very hard-to-find bugs.

RayLivingston:
The point of an enum is it creates a new type, and a variable of that type can ONLY be set to the value of one of the enums. You CANNOT do that with #defines. That, and what you just saw with the calculation example, are perfect examples of WHY type-checking is important, and why const variables and enums are better/safer to use than #defines. Arguably, at this point, #defines should be used only for macro definitions, controlling pre-processor conditionals, etc.. Even then, they must be used with great care, or you can create some very hard-to-find bugs.

Absolutely ! Thank you so much for the profound answers. I got the idea now more clear.

wolfrose:
Oh yes, I like your arrangement of logical states and const values you use constexpr.
So what I understood until now is that:

  1. constexpr could be more optimized than define
  2. sharing the properties of const and defines
    Are my conclusions right ?

constanst's are constants and defines are really a whole different subject which is kinda why they shouldn't be used as constants even tho that is what they are. Cunfusing? yes. At this point I haven't found an actual need for them so I haven't bothered trying to sort it further.

The way I understand it constexpr fixes a loophole in const. Where if you create a reference or pointer to a const variable it can then be changed and is no longer actually constant.

Hutkikz:
constanst's are constants and defines are really a whole different subject which is kinda why they shouldn't be used as constants even tho that is what they are. Cunfusing? yes. At this point I haven't found an actual need for them so I haven't bothered trying to sort it further.

Of course, it takes me time to get not the whole picture of something, but maybe to get that point more clearer and also get a more depth understanding of that point. So yeah, I may start using constexpr and it should work just fine, and maybe later with the more use of it, to learn more about it for God's will.

The way I understand it constexpr fixes a loophole in const. Where if you create a reference or pointer to a const variable it can then be changed and is no longer actually constant.

Yeah, you mean using the value of that const and put it in a variable and be able to change it. Is that what you mean ?

wolfrose:
Yeah, you mean using the value of that const and put it in a variable and be able to change it. Is that what you mean ?

No, if you put the value of a constant into a variable, you will always be able to change the value of the variable.

Read it again.

wolfrose:
Of course, it takes me time to get not the whole picture of something, but maybe to get that point more clearer and also get a more depth understanding of that point. So yeah, I may start using constexpr and it should work just fine, and maybe later with the more use of it, to learn more about it for God's will.

Trust me your not alone. I've been at this for a good while now and am only a tiny bit further along than you. TBH I'm kinda proud of how I seem to be doing in this thread. Usually others would have needed to correct me by now. :grin:

Let's see if I can keep it up:

Yeah, you mean using the value of that const and put it in a variable and be able to change it. Is that what you mean ?

A constant should never change during run time. Therefore it does not need to be placed in memory(RAM). it can instead be placed in the program space(Flash) and most of the time it is.

A pointer is an ordinary variable that contains a special type of data. That data is the address of another variable. If you have a address of something you can then change the value of the data contained in that address. That address must be in RAM and not in Flash.

Now if you create a pointer to a constant then the compiler is forced to place that constant in RAM so that the pointer has an address to point to.

The loophole is that while you still cannot change the value of this constant directly it is possible to change it by using the pointer. Therefore the constant is no longer actually constant and you will get no errors from the compiler. When you use constexpr the compiler will not allow you to create a pointer( or reference) to it.

The reality is that with the small programs that will fit on a arduino usually written by only one person it is not likely you will make pointer to a constant but constexpr guarantee's that you can't do so by mistake.

Hutkikz:
If you have a address of something you can then change the value of the data contained in that address.
That address must be in RAM and not in Flash.

Taking the address of a constant does not allow for changes to the constant, it is still a pointer to a const object.
You have to cast it to something non-const to allow changes.

A constant has to be placed in RAM if its address is taken, because there is no concept of a pointer to flash.

Hutkikz:
Trust me your not alone. I've been at this for
The reality is that with the small programs that will fit on a arduino usually written by only one person it is not likely you will make pointer to a constant but constexpr guarantee's that you can't do so by mistake.

What you do sometimes see is someone declaring a char* and initializing it to point to a string constant, then latet in the code using the pointer to alter the string. Can lead to odd behavior when the compiler sees multiple occurences of the string and optimizes the code to only store a single copy.

david_2018:
What you do sometimes see is someone declaring a char* and initializing it to point to a string constant, then latet in the code using the pointer to alter the string.

So make sure to allow all warnings, check and fix all of them.

Somewhere\constString\constString.ino:1:11: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
 char* x = "constString";
           ^~~~~~~~~~~~~