const vs #define unintended functionality?

Hi,

I'm in the process of cleaning/optimizing up my C++ code and came across something interesting. While trying to reduce RAM usage I'm thinking to use constant strings and put them in program memory using PROGMEM.

My original code had some defines like this:

In .h file

#define someDEF1 "This is string1 "
#define someDEF2 "string2"
#define someDEF3 "string3 "
#define someDEF4 "string4"

in my .cpp code to 'concatenate' the strings and print it to the serial port I just use

Serial.print ( someDEF1 someDEF2);
Serial.print ( someDEF1 someDEF3 someDEF4);
Serial.print ( someDEF1 someDEF2);

sort of a concatenation effect.

I understand that at compile time the c++ compiler replaces every #define it encounters with the string (in this case) equivalent and place it in program memory so no RAM is used... good as I want this behavior but there is a catch, duplicity and wasted space as every #define use additional separate memory space. So in line 1 and 3 of the code section above it the Serial.print occupies separate memory spaces for the same string (some DEF1 someDEF2 = "This is string1 string2").

Now the situation: When I create a constant string using PROGMEM I make one and only one instance of that string so if I reference this string anywhere in my code it will be the same memory space (no wasted space or duplicity) but to concatenate the different strings I would have to add additional code as Serial.print (const1 const2) will not work.

.h file

const char const1[] PROGMEM = {"This is string1 "};
const char const2[] PROGMEM = {"string2 "};
const char const3[] PROGMEM = {"string3 "};
const char const4[] PROGMEM = {"string4"};

.cpp file

String st;

// THIS WILL NOT WORK
Serial.print ( const1 const2);

// SOLUTION
st = const1;
st.concat (const2 );
Serial.print (st);

So defining a string object will work but additional code will be needed and for me harder to visualize.

Question: Is there anyway to recreate the simplicity of using #define while using const?

Moderator edit: tags corrected

You have it completely wrong.

define is a pre-processor direvtive

define bill fred

change all occuances of bill to fred it has nothing what so ever to do with progmem.

#define someDEF1 "This is string1 "
#define someDEF2 "string2"
#define someDEF3 "string3 "
#define someDEF4 "string4"

Serial.print ( someDEF1 someDEF2);

will give you

Serial.print ("This is string1 "  "string2" );

I understand that at compile time the c++ compiler replaces every #define it encounters with the string (in this case) equivalent and place it in program memory so no RAM is used.

Completely wrong!

Mark

Look up using F macro. https://github.com/arduino/Arduino/issues/2579

will give you

Code: Serial.print ("This is string1 " "string2" );

When what you really want isSerial.print (F("This is string1 "  "string2") );

holmes4: You have it completely wrong.

Maybe I wasn't clear enough, from this link https://www.arduino.cc/en/Reference/Define

define is a useful C component that allows the programmer to give a name to a constant value before the program is compiled. Defined constants in arduino don't take up any program memory space on the chip. The compiler will replace references to these constants with the defined value at compile time.

That quote is incorrect. Some small numbers (constants) can be part of an instruction. I try never to look at the asm but as I recall the limit for that on the avr's is 5 bits.

Other than that they must take program space and unless you say that they are "PROGMEM" then they also take up SRAM/ strings are a good example of this but it also applies to all types.

Mark

LarryD AWOL

AWOL: When what you really want is

Serial.print (F("This is string1 "  "string2") );

Ok, interesting.

Back to my original question, when I use Serial.print (F("This is string1 " "string2") ); both strings are stored in program memory right? Where exactly in memory?

Now if I use the exact same code (Serial.print (F("This is string1 " "string2") );) in another place in my sketch where will both strings be located in memory? At the same memory location as the first Serial.print? If not then I will have two different memory locations in flash with the same data (strings) I call that duplicity and therefore wasted space.

thanks

I believe string constants in the same compilation unit are merged but string constants from other compilation units are not. I suspect the avr-gcc folks have documented the behaviour. It is certainly easy to test.

I call that duplicity and therefore wasted space.

It is only a waste if you run out.

Exactly my point and therefore my concern/problem… running out of RAM.

The project I’m working with use a lot of strings, for debugging, user interface, screen control, data acq, communication among other things.

Yes, testing is what I’m going to do this weekend. I already created an empty sketch to see how this things work, add this to the lack of compiler listing options other than avr-bjdump (that I know of) makes the task a little bit harder.

My skills are from another architectures with less resource constrains and perhaps from another era :wink:

Anyway thanks for all the responses.

BTW If someone knows how to create detailed compiler listings I’m all ears eyes.

starstuff: Exactly my point and therefore my concern/problem... running out of RAM. ...

Remember above where the print (F( construction was mentioned? When you use it, the string does not use any RAM.

See: http://gammon.com.au/progmem

BTW If someone knows how to create detailed compiler listings I'm all ears eyes.

http://www.gammon.com.au/tips#info1

[quote author=Nick Gammon link=msg=2567657 date=1452925717] See: http://gammon.com.au/progmem

http://www.gammon.com.au/tips#info1 [/quote]

Excellent tips a good start for my tests.