Arduino And Pidgin C++

What do you program the Arduino in? C? Actually, the Arduino’s byzantine build processes uses C++. All the features you get from the normal libraries are actually C++ classes. The problem is many people write C and ignore the C++ features other than using object already made for them. Just like traders often used pidgin English as a simplified language to talk to non-English speakers, many Arduino coders use pidgin C++ to effectively code C in a C++ environment. [Bert Hubert] has a two-part post that isn’t about the Arduino in particular, but is about moving from C to a more modern C++.

Even those of us who use C++ often use what we think of as “classic” C++. More or less the C++ that started life as a preprocessor in front of the C compiler. C++ has changed a lot since then, though. [Bert] looks mostly at useful features from the C++ 2014 standard which is widely available in compilers now. He only talks a little about some 2017 features. He doesn’t, however, talk about super new features or very specialized features that probably won’t be your first stop in a transition from C.

In particular, [Bert] doesn’t cover multiple inheritance, template metaprogramming, a big chunk of iostreams, C++ locales, user-defined literals, or exotics. Just to motivate you, he shows an example where calling the C library to sort a large array is slower than the code using C++ templates that take advantage of parallelism. While this is a special case, it does show that C++ isn’t just “another way to write the same thing.” You could write a faster sort in C, but you’d be writing a lot of code, not just pulling in a library.

What he does cover is strings, namespaces, classes, smart pointers, threads and error handling. Some of these will be more useful on the Arduino than others, but if you are writing for other platforms like a PC or a Raspberry Pi you could use all of them. He’s planning on adding more items in future installments of the series.

Meanwhile, we had our own story about modern C++ and the Arduino last year. If you want to know more about templates, we’ve talked about that, too.

87 thoughts on “Arduino And Pidgin C++

  1. I usually think it’s best to use what you know.

    I do write code in C++ environment most of the time, but I’m more versed in C.
    Every time I write a code I try something new in C++.

    This way I write a code that’s not a complete mess, as can I handle myself well in C, and still learn something new in C++.

    1. Modern gcc and clang compilers are actually not as terrible as people say, but most people _still_ write in C without really admitting it’s a style choice of linear programming fans. Personally, I prefer C for resource-limited RT hardware development, and C++ for applications with dozens of well-tested libs.

      The GSL is like candy :)
      https://www.gnu.org/software/gsl/

      But libs like wxwidgets do weird things outside the standard styling that is normally expected, and takes a bit to learn the dialect philosophy.
      https://www.wxwidgets.org/

      I guess the two languages sort of diverged in function a long time ago, and saying one tool is better/worse will always be incorrect depending on the users’ needs. I find clang does make most code faster, but it also offers some of the nastiest runtime bugs if people like to get creative with hold-my-beer coding tricks… you know who you are ;-).

  2. In particular, [Bert] doesn’t cover multiple inheritance, template metaprogramming, a big chunk of iostreams, C++ locales, user-defined literals, or exotics.

    Is that constructive criticism?

  3. It’s probably just because I’m not used to it, but all the colons and larger-than and smaller-than signs all over the freaking place makes C++ look messy and harder to read than C.

  4. I’d like to use modern C++ with `auto`, lambdas, new `for` loop etc but …

    avr-g++.exe –version
    avr-g++.exe (GCC) 4.9.2
    Copyright (C) 2014 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions. There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    1. You make it sound like building a newer gcc targeting AVR is an impossibility:

      $ avr-gcc --version
      avr-gcc (Gentoo Hardened 7.3.0-r3 p1.4) 7.3.0
      Copyright (C) 2017 Free Software Foundation, Inc.
      This is free software; see the source for copying conditions. There is NO
      warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  5. Why do people insist on coding in slow languages? C is slow, C++ is even slower!

    Java should be the default language. Java makes everything go faster! Once the hotspot compiler runs, applications are at least 10X faster than in C, and 100X faster than assembly.

    I know Java is harder than C/C++, but since it’s sooo much faster, it’s worth the extra investment.

    C/C++ is good for code jockeys and “hello world” programmers. If you are building a real app, just use Java.

      1. Provided you have the correct java version, the correct class libraries, enough memory [8gb should be enough for most trivial programs] , a quad core cpu, and 10gb of disk space.

    1. Java is slowish as well. I am curious, is there any advantage in memory, speed or libraries in C or C++ that make either more desirable? A unique native data type that improves processing? I would think the overhead of class inheritance would reduce code efficiency. The only advantage I can imagine is that you might use headers + classes to implement a psuedo library of some more modern language. Does this impact FPG processes?

      1. There is no data type unique to C (or C++) that makes it better suited to any particular environment – all data types are to some degree dependent upon the environment itself, and more complex or esoteric data types implemented on hardware with no native support for them will always be less efficient.

        And don’t assume that the “overhead” of class inheritance makes for larger and/or slower code – I have seen plenty of cases where inheritance makes code smaller, faster and more memory efficient, And easier to maintain.

        1. “And don’t assume that the “overhead” of class inheritance makes for larger and/or slower code”

          In fact, assume the opposite. I realize that the latest C++ compilers don’t convert to C first, but for compilers that DO convert to C before actually compiling,almost all of the class inheritance stuff disappears in the C code.

          Which brings up another point: even beyond the basic principle of Turing machines (extended to languages), i.e., anything that can be written in one Turing-complete language can be ported to any other, all of the features of C++ can be implemented in C. You want polymorphism? Just include one more argument to all of your functions, that tells what type you expect it to return. Anything that can be done with a class can be done with a structure; you can even put function pointers into the structure. Yes, I’m oversimplifying, so don’t bother telling me “that doesn’t work for ___ case”, because obviously the C++ preprocessor can make it work for ____ case.

          I try to avoid C++; when i write Qt applications, I do the back end processing in C, but the next-best thing is just writing C++ functions without using any C++ extensions. Which means it doesn’t bother me that Arduino sketches are C++ programs.

    2. C is slow if you write it slow. C++ is slow if you write it slow. Any language is slow if you write it slow.

      But given that virtually all of UNIX was ported to C from assembler in the mid-70’s, I’d say it’s pretty fast. But until someone ports UNIX to Java and shows that it can actually run faster on the same hardware (and leave enough memory to run your applications) you’re talking through your hat.

        1. I was born sarcasm-deaf – I can only detect it by listening for the beat frequencies generated by mixing sarcasm with sincerity.

          Either that, or by reading the entire post before popping off….

  6. IIRC, the Arduino standard library is the pinch point. std::vectors are the backbone of C++ and they don’t work in arduino. I think there’s a similar problem with strings (hence the Stribg in arduino).

    The ESP compiler does have standard template libraries and modern c++ features and I’ve use lambdas to make the use od the freertos tasks. It’s great. The esp if also significantly faster though.

    1. And to get a lot of really nice algorthms done in C++ without custom data structures what you need is the STL map template. If you want to basic minimax or A* AI decision making, or run Djikstra’s algorithm, or some horrendously complex state machine, maps make life easier.

      1. A map is a binary tree, and trees need dynamic memory allocation. That doesn’t play well with the Arduino’s limited memory space.

        But then, why use an Arduino today when you can have an ESP32?

    2. Dynamic memory allocation is a bad idea on embedded devices. You can’t code for them the same way you would on a desktop machine with gigs of memory and swap that you can reboot occasionally if there’s a memory leak.

      1. Dynamic allocation was invented on systems smaller than some of the microcontrollers we use now, in order to get around some of the restrictions of the hardware in a semi-manageable way. It SHOULD be considered a rickety bridge to functionality and not used if avoidable, but…deadlines.

      2. In Python I’m used to getting away with having arbitrary size lists or strings etc. On a Desktop, I don’t mind too much if my 100 lines of Python uses 50% of my CPU and 50% or ram. I’m learning C and finding it very different (strings are fixed size arrays etc.) but this seems more intuitively connected to the hardware and limited RAM. Then I see Strings (capital S), which I think are C++, and these seem much more like the things I was ‘getting away with’ in Python.

      1. To be dynamically sized data structure classes store their actual data on the heap instead of the stack (so you need one of those which an AVR might not have). Also RAM fragmentation. If you new and delete a bunch of differently sized allocations on the heap you can end up with no contiguous chunk of free memory large enough to fit a new object later. There are ways to get around it with “placement new” where an object is constructed on a pre-allocated pointer in memory but it requires a mechanism for feeding a block of allocations to the data structure to work from. I think there may be a way to do this with the STL allocator system but I don’t understand that system yet, and the default approach would end up being the one that doesn’t work, which is not a great place to be functionality wise. Also, using pools to prevent fragmentation more or less doesn’t work at all with the entire family of variable length contiguous data structures like vector and String (and possibly unordered_map, it depends if the number of buckets ever increases).

        This is a pretty general problem with embedded systems which is why I mention it even though an AVR might not have the RAM to run a memory-intensive AI or routing algorithm.

    1. The standard Arduino style for writing libraries abstracting hardware functions is to write them as C++ classes – Serial, Stream, print, String, EEPROM, Wire, SPI, Servo, etc. are all C++ classes.

      Most higher-level capabilities of C++ classes are not commonly used because the platform was designed for beginners, not programmers with many years of experience. But Print, Stream and Serial all use – *gasp* – inheritance and polymorphism (virtual functions).

  7. I think that some of the the C++ features SHOULD be used more by people writing code for the ardunio.. Apart from making the code easy to debug (and get right the first time) even on an ardunio, once you start writing bigger programs from other chips ie 8266 and esp32 it becomes more essential.

    Mainly –
    1) using classes for encapsulation STILL has all the benefits on an embedded chip as it does on a bigger computer.
    2) simple single inheritance is still very very useful for many many things… Including abstract classes.
    3) polymorphism still makes code a hell of a lot cleaner!

    Sure, you aren’t going to have a tight loop doing something to hardware that includes a features that takes time. But the bulk of your code – and where many of your bugs will be – is NOT in a tight loop, and the time taken for a pointer deference (for example) is irrelevant – and the code is much easier to get going to start with, easier to maintain, and easier to modify..

    1. Ian-42 and Al,

      Want to put your heads together and produce a short article with some examples? I went to the linked article(s) with high hopes, but came away realizing I needed more coffee (like a Pacific ocean’s worth) before I “got” how to plug all of that into an Arduino program for the ESP.

      1. Search Hackaday for “Embedded C++” or Rud Merriam. You’ll find a number of examples of C++ on the Arduino.

        I’ll toss it out here even though not directly a reply, but if you look at the newer boards and some of the older ones like the Due you’ll see plenty of memory room to work with C++.

  8. use whats best for your task at hand, dont do it because others do it, do it because you know how to get the job done and F everyone else. Personaly, I use C for a micro and I look at the ASM listing all the time in criticial sections and I rewrite some of my C to try to optimize my goals.

    Now its just my opinion, I want least overhead in my code and dont use C++ nor would I ever bother with a uOS that adds overhead and that had features not really needed, but hey, just an opinion and I am sure there is going to be a ton of jack asses saying otherwise replying to this post. Maybe I am just tired of poor programmers complaining, I can get a Simple PIC18 to do 32 servo outputs at 250Hz without any type of multitasking no speacial hardware crap either.

    Put on your big boy pants and learn to program when it comes to microcontrollers where memory, bytes are at a premium. When I design for a client, a $2 difference in chips means 2.6 retail factor, so that $2 chip with more memory becomes $5.2, that times 100,000 shipped units is $520,000 increased retail price or 1.2 million in lost revenue,

    rant over, flame on

    1. One of the most important goals Bjarne Stroustrup had when creating C++ was to make sure C++ was just as efficient as C. Obviously that depends on how good the compiler is but I would imagine the developers behind G++-AVR would have efficiency of the optimizer as a priority.

      Oh and remember that this stuff was running on things like VAX systems with very limited resources (RAM in particular). If C++ can run on a VAX-11/780 with acceptable performance, surely it can run on an ATmega328P with similarly acceptable levels of performance…

    2. Well, we are talking ardunio etc here, and I’d be surprised if the few C++ things I mentioned above would cause something not to fit on the chip. I’d recon (from what I’ve seen) the biggest problem most people have with the ardunio is RAM, followed by bloated libraries, and the interaction of the two. Couple with using features they are better of not using like floating point, strings (instead of managing their own char *), and printf… etc.

      Where adding in encapsulation, SIMPLE inheritance, and polymorphism (where it is needed) vastly makes the code more reasonable AND doesn’t use much in the way of resources…

      And I did follow the links in the article, and agree with [PuceBaboon] above – that ISN’T what I would have said for people wanting to move from C to C++ on the ardunio…

      I’f I get time – always the problem – I’ll write some articles about what I’d recommend a amateur C program do differently with access to C++ on the ardunio… :-) And then we can all have an argument about it…

    3. C++ usually adds no overhead on memory or timing. It can even reduce memory usage. Mentioned it in another reply but read my articles on HAD. Search for Embedded C++ or Rud Merriam.

      C’mon guys, the same dang compiler is used for both C and C++. They generate the same code.

        1. Virtual methods, where used appropriately, are the one C++ feature that every programmer should learn and use because they often end up producing both smaller and faster code than the alternatives in C – a long series of if..else if… statements testing a single variable against multiple values, a large switch statement, or a set of function pointers. (In fact, virtual functions are exactly what the last option is, except it’s a table of pointers which is always initialized for you with less overhead, exists just once for each class of object, and cannot be broken by a mistaken assignment.)

          At runtime you never have to test if the object is an A or a B or a C like you would with ifs – the object already knows what type it is, so the tests (and the clock cycles they consume) are eliminated – all you have to do is de-reference a single pointer. So, speed – and you gain more the further deep you have to go into the list of tests (which is, not coincidentally, precisely why the switch statement exists),

          And the vtable (virtual method table) in a class with virtual methods is no different than the jump table a switch statement will usually produce. Except you never have to perform the test at the top of the switch, the vtable is always densely compact regardless of how sparse your test range is, and it only has to occur once for a given class rather than in every single place you might have to test an object’s type to determine what action needs to be taken.

          And the overhead cost when it comes to the size of the objects themselves is usually none, since the vtable pointer replaces the member you would otherwise need to have to track the object’s type. In fact, with polymorphism in C++ you often end up using less memory overall, since objects lower in the class hierarchy never need to allocate space for members introduced and only used by more derived objects, nor do they have to initialize those members.

  9. .. and while I was typing that, someone commented about the VAX-11/780- I used to (in the 80’s) process satellite data with a VAX, and it was all written in C++, with some individual routines (still encapsulated) in assembly. Exactly what I do in an embedded processor today!

    I’ve done that on very big machines (big mainframe as well) ie write it all in a good clean high level (relatively) language THEN write the bits that need to be in assembly.

    The current project I’m working on has about 50K lines of C++ and a handful of assembly routines…

    1. The original Borland C++ compliers had a switch for the command line that would spit out assembler code rather than object code as the final output. I would take selected parts of that and hand-tune it for the timing-critical stuff.

      1. same here – but I also have done that with a lot of other compilers ie the mainframe pl/1 compiler did that too! It was sometimes quite amazing to see how much code was generated to do simple things – but they had to take every possibility into account..
        And I agree with your other comment on virtual above. And and that even if all what you said wasn’t true (which it is) it just makes the code so much easier to write and maintain!

  10. It is evident how clueless about C++ the designers were when they decided new is unacceptable but malloc isn’t, and went on gutting half the language by deliberately disabling new.

    It came as a surprise, but after reading the comments here, apparently there are plenty of people like that.

  11. On embedded devices libstdc++ is not usable and C++ is really mostly about the ability to use ADTs.

    The rest is mostly syntactic sugar with the huge problem that sugar always brings to the table if you’re not careful: obesity. I tend to avoid C++ on those devices because nothing is more annoying than trying to figure out which statement or missing declaration the hell just bloated the generated code so much that its larger than the available flash or even more annoyingly RAM.

    1. “syntactic sugar” – That turns out not to be the case.
      And the biggest bloat statement I’ve seen people use on an ardunio is something like

      float ratio = 5.46/7.85;

      which causes the whole floating point library to be included…

      1. Yep! dont get me wrong, I like C++, but I just dont take advantage of most of it, and when it comes to micros, I feel a novice programmer who abstracts everything would just bloat and fill the poor micro.
        Example: I helped a programmer with a GPS device that did tracking and projections, every variable they used was a float, I just made each a 32bit number and knew that we just assume a 4 place decimal, so when we printed anything out we knew divide by 10,000 Kinda like when you work with money, you do everything in cents; ie: $1.50 is 150 cents.

        just my (2 / 100) cents

      2. This is a fantastic example. It shows precisely why C and C++ suck badly: the simple and obvious thing is the worst possible solution. Omitting the trailing f on the constants means that the numbers are instantiated as doubles, the divide is a double-precision divide, and then the result is cast to float. And then the value is placed in RAM even though it’s probably a constant. Total train-wreck.

        A far better approach is:

        #define ratio (5.46f/7.85f)

        Hopefully the compiler will figure out that it can do the divide itself but of course there is no guarantee. There are probably a dozen different ways to express this in C++, most of them are badly flawed but still perfectly valid code and the compiler will happily generate an awful mess.

        Anybody who thinks that C++ is a good programming language, fails to understand that C++ code must be written by members of the species homo sapiens. They also fail to see any relevance to the thousands and thousands of CVE reports created for C++ programs.

          1. I can almost guarantee that any such implementation, while indeed the smallest and fastest implementation, will suffer from edge-case bugs and compiler incompatibilities unless subjected to extensive unit testing. And even if you get it to work right in the first place, you will need to keep the guy who wrote it, because nobody else will ever be able to debug it. This is why Microsoft has such difficulty maintaining the Windows code base, it is chick full of lovely performance enhancements that are incomprehensible to their current developers.

        1. And yes, I sort of agree about C++ – using it in its ‘entirety’ does requite more skill than the average corporate programmer.
          But then the problem is, what do you write in if not C++? No other language comes close if you are writing a large system (NOT talking about embedded here).

          Java is unusable apart from relatively trivial things, languages like PHP – which is good for what is is meant for – are ok for some web site stuff etc – but what else is out there?

          We simply haven’t had a real step forward since C/C++ if you want to build a big production system, though I agree using a subset of it is more the way to go..

          1. The “pragmatic” answer is that you write a domain-specific language implementation in C++ and then move application development to the domain-specific language. For examples: emacs, AutoCad, gimp, etc. Implement all the low-level stuff in C or C++. You’ve segregated the software effort into two camps: low-level stuff done by a couple of C++ gurus, and then you can hire developers that haven’t memorized Stroustrup to write the application code. If you design the interfaces well, you can throw subsequent resources at optimization of the low-level code without disturbing your investment in high-level code. In the long term we need better hardware with tagged data types and a new language to go with it.

        2. F: using your “#define ratio (5.46f/7.85f)” example, if you try using this with integer variables, it’s going to get evaluated as (int)(5.46f/7.85f), which equals 0. This is probably not what you intend.

      3. “float ratio = 5.46/7.85;
        which causes the whole floating point library to be included…”

        How is this a bad thing? If you need floating point, you need the floating point library, simple as that. There are times when you really want to avoid using floating point, such as when dealing with money, or with counting frames in video, but it is just as bad to use int when what you really need is float. If you use int, you have to be careful at every single calculation, that your result won’t overflow or underflow. And if you just give yourself enough margin on both sides by carefully choosing your multiplier (like 100 for expressing dollars as cents, or 1000 when expressing time in milliseconds), you’re still limiting your dynamic range. If you need to multiply a number by 19/32, using integers, you have to be careful about the order – multiplying by 19 and then dividing by 32 does not give you the same result as dividing by 32 first and then multiplying by 19. But in float, multiplying by 19f/32f always gives you the right answer.

        1. I’ve seen way more problems introduced with float than with using int instead..

          But ignoring that for the moment, many times I see floats in ardunio code simply because the eprson hasn’t thought it through – as the float library uses a lot of RAM…

          The most common one is
          float distance = read_ultrasonic(D1); // where read_ultrasonic returns a float

          which returns the distance to something in cm, with all those decimal places.

          It’s much faster – and much better on resources if you keep the float library away – to do

          uint16_t distance = read_ultrasonic(D1); // where read_ultrasonic returns a uint16_t

          and have the result returned in mm or cm (etc). There is nothing IN reading and ultrasonic that needs a float, and this isa more sensible result given the precision of the instrument..

          I find that if you keep floats away whenever you can, you often end a project without using need to use them… :-) And referring to one of the comments many posts above – having float vs not having float, CAN make a big difference to something that will fit on a chip to something that can’t…

          1. Yes, you give a good (straw man) example of where a float is not necessary. I was talking about when you actually DO need floating point numbers. I thought I was pretty clear – there are right and wrong places to use float. If you don’t need them, don’t use floats. Duh.

  12. Yes, you give a good (straw man) example of where a float is not necessary. I was talking about when you actually DO need floating point numbers. I thought I was pretty clear – there are right and wrong places to use float. If you don’t need them, don’t use floats.

  13. So, I’m going to bridge two comment threads, here (the other being https://hackaday.com/2018/06/22/linux-fu-the-great-power-of-make/): I don’t even remember what an “Arduino” is. I hate IDEs, so even though “Arduino clones” are the cheap and easy way of getting dev boards for Atmel microcontrollers, when I have something I want to use an AVR for, I use a text editor to write C code, then use make to compile, link, convert to hex, and program the device. I got the examples for how to set up the whole flow from [Adafruit]. Thanks, guys – I don’t even have the Arduino IDE on my machine any more.

    1. well, I agree, the ardunio IDE shouldn’t even be called a ide, its a piece of crapware. And I too have often just used a text editor with make hanging off a function key.
      However, I do find eclipse – even though it is stupidly written in java which means it can really only handle one mid sized project at a time – is useful as a editor front end to make. It nicely puts all your project files in one window, the make output into another window, and the serial port in another.. Of course, it can use a GB or two of RAM to do that (thank you java…) and the index function (if turned on) takes longer to work than making a cup of coffee does…

      As I don’t use any of its ‘advanced’ features, one of these days I’ll write something that can do something similar but can handle more things open at once… The again, I don’t think I’ll ever have enough time to write everything I want written.. :-)

  14. The 2048 bytes of RAM limit on the Uno is very strict. Using C++ would even make it worse. If you use virtual methods then their pointers are stored in RAM. What is totally useless if you only have a single type of object instantiated – what is usually the case in Arduino programs. If you don’t use virtual functions then using C++ is useless.

    For these reasons I stick with C on Arduino. I only use C++ when I access libs written by others in C++. TBH I don’t like C++ on a PC too. I program complex things in Java or C#. And when I have to use some low level API then I implement a thin JNI layer between Java and the API.

    Instead of wrapping strings into C++ objects I better use strings in PGMSPACE. This way they do not use our valuable RAM. Instead of:

    Serial.print(“BLA-BLA”);

    I use
    PRINT(“BLA-BLA”);

    #define PRINT(s) (my_print((uint32_t)PSTR(s)))

    and

    void my_print(const PROGMEM char * ptr)
    {
    char ch=pgm_read_byte(ptr);
    while(ch !=0)
    {
    Serial.print(ch);
    ptr++;
    ch=pgm_read_byte(ptr);
    }
    }

    Spare RAM! Do not waste it!

    1. Hmmm, that example is a complete waste of RAM…
      Haven’t you seen F()???
      Serial.print(F(“BLA-BLA”));

      The string is now NOT stored in RAM… And you don’t have to rewrite all Serial.print can do…

      And yes, progmem is important, and is where you should store most strings. However, that is no reason not to use a few C++ features – and on a PC I find it hilarious that you don’t want to use C++ because of the overhead, but you use java..

    2. >> If you use virtual methods then their pointers are stored in RAM.

      No, they’re not. The pointers to the functions reside in a table (the vtable) in Flash, and RAM contains only a pointer to that table. Try this on an Arduino sometime (or the equivalent on whatever your preferred platform is):

      class A
      {
      public:
      virtual int a();
      virtual int b();
      virtual int c();
      };

      int A::a() { return 1; }
      int A::b() { return 2; }
      int A::c() { return 3; }

      A a;

      void setup() {
      Serial.begin(115200);
      Serial.print(sizeof(A));
      a.a();
      a.b();
      a.c();
      }

      void loop() {

      }

      The output from the above is “2” – there’s no way that pointers to three functions can fit in just 2 bytes. Add another 3 virtual functions to the same class and you’ll fund that sizeof(A) still returns 2. Those two bytes are the pointer to the vtable. All good C++ compilers will do it this way regardless of the platform – the vtable always goes into code space, not data space, regardless of how each of those happens to be implemented. And there’s only one copy of it per class – essentially, it’s a hidden static data member.

      Your point about putting invariant strings in Flash is important, though. Not only does it save RAM, it saves Flash memory as well. That may sound counter-intuitive, but literal strings always start out in Flash or there’s no way they could be initialized at runtime. But if you don’t keep them in Flash where they belong then there’s a bunch of code that has to run around initializing all those RAM strings with with the Flash copies before anything else can be done.

Leave a Reply to ian 42Cancel reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.