4

I'm creating software for an Linux + AVR Arduino project. Obviously the whole work is split in several projects in Eclipse (I'm not using Arduino IDE). I'd like to use common, mostly string, constants for all those projects. I also have to spare microcontroller's RAM so compile-time constants needed. How do I best implement it? My idea is to create a separate, header-only, project for those constants.

Using:

class A {
public:
    static const char * const STRING;
    static const unsigned char BOOL;
};

is not good enough, because I'd like to be able to concatenate string constants like this:

class A {
public:
    static const char * const STRING_PART1;
    static const char * const STRING_PART2;
    static const unsigned char BOOL;
};
const char * const A::STRING_PART1 = "PART1_";
//const char * const A::STRING_PART2 = A::STRING_PART1 + "PART2"; //obviously won't compile
//const char * const A::STRING_PART2 = strcat("PART2", A::STRING_PART1); //this is not compile-time

I also don't want to use define. I'd like to use:

class A {
public:
    static const std::string STRING_PART1;
    static const std::string STRING_PART2;
}

which allows for string concatenation and is (AFAIK) compile-time, but std::string is not available in avr projects - or I'm wrong here and just don't know how to use it.

Any help appreciated.

mmm
  • 1,277
  • 5
  • 18
  • 34

2 Answers2

3

You can continue with the current idea of using const char* const (if std::string is not usable). I would suggest to use #define for assignment purpose only. Example:

class A {
public:
    static const char * const STRING_PART1;
    static const char * const STRING_PART2;
    static const unsigned char BOOL;
};
#define PART1_ "PART1_"  // <--- for value assignent
#define PART2_ "PART2_"
const char * const A::STRING_PART1 = PART1_;
const char * const A::STRING_PART2 = PART1_ PART2_;  // <--- ok! concatenation by compiler
iammilind
  • 68,093
  • 33
  • 169
  • 336
  • Thanks iammilind, this compiles, but: I don't want to pollute the global namespace with defines (yes, I could undefine them after initialization, but that's not clean IMHO), and mostly, the second constant is not compile-time (just checked that, adding adds 16 bytes to overall memory usage, don't know why 16). – mmm Sep 07 '11 at 08:55
  • @mmm, ofcourse 2nd constant is **at compile time**. It will add some memory usage, because you have 2 strings now. `"PART1_"` and `"PART1_PART2_"`; the sizeof 2nd string is 14 bytes. Had it been not at compile time then it would have been a compiler error. – iammilind Sep 07 '11 at 09:02
  • hmm, either I don't understand what compile-time constant means, or you're wrong, but I'm not assuming this yet. For me, a compile-time constant means, it doesn't use any RAM memory in runtime, because it's hard-coded by compiler. Your solution, even if this seems illogical, uses RAM in runtime according to avr-g++ statistics shown while compiling. It says: Program: 97362 bytes (74.3% Full) Data: 7660 bytes (93.5% Full), whereas there is 16 bytes less data without the second constant. The first one only adds 2 bytes, which I also don't understand yet, assuming its just the core pointer's size. – mmm Sep 07 '11 at 09:06
  • @mmm, compile time constant doesn't mean it doesn't use memory. Without memory where it will be stored ? It has to be stored in some memory region and that's decided by compiler. – iammilind Sep 07 '11 at 09:10
  • Compile time for me means it is stored in ROM (eg. microcontroller's flash), where as runtime variables are stored in RAM. In my case, it's RAM I have to spare. The compiler decides where to put variables basing on many rules. Defines are one example of compile-time constants, they clearly don't count up to RAM usage. An other example should be static class constants - but in this case my compiler decides otherwise. Of course, I may be confusing things. – mmm Sep 07 '11 at 09:17
  • OK, after longer testing I must agree I was partially wrong. The compiler puts the variable in RAM as long as it's not used (and in my tests before I didn't use the second one, I just declared it). When it's being referenced in code, it's being moved to ROM. Strange are the paths of compilers' optimization. Thank you again iammilind. But there is another issue: if there will be constants I'll use only in the AVR project, I'll waste RAM. So this sadly is not a solution to my problem. – mmm Sep 07 '11 at 09:50
1

Compile time for me means it is stored in ROM (eg. microcontroller's flash), where as runtime variables are stored in RAM. In my case, it's RAM I have to spare. The compiler decides where to put variables basing on many rules. Defines are one example of compile-time constants, they clearly don't count up to RAM usage. An other example should be static class constants - but in this case my compiler decides otherwise. Of course, I may be confusing things.

I think that you're in fact confusing things:

  • defines are not stored in ROM - they are not part of your program at all as they get evaluated by the preprocessor already.
  • the difference between "compile time" and "run time" you're making applies to evaluation, not storage.

If you want to use program memory (= AVR flash) for constant strings, use the PSTR macro from avr/pgmspace.h.

  • By ROM I meant defines are being evaluated and translated to binary form and as such "stored" inside the compiled source code. So I guess I'm not confusing it, just possibly not calling it right. The thing I'm trying to achieve here is to store constants in a nice, gcc and avrgcc compatible fashion, and not waste RAM for it. – mmm Sep 07 '11 at 12:51
  • yeah, #defines are *not* translated to binary - in fact, the compiler doesn't get to see them at all because the preprocessor evaluates them already. The compiler sees the same if you write "foo" or FOO if you #define FOO "foo". – hackotronic Sep 07 '11 at 13:04
  • `` and `PSTR("foo")` is _exactly_ what you want to use if you have more flash than RAM. – hackotronic Sep 07 '11 at 13:07
  • check the manual for "Data in Program Space": http://www.nongnu.org/avr-libc/user-manual/pgmspace.html – hackotronic Sep 07 '11 at 13:50