C++ version Compiler

I charged now the latest IDE 2.3.3 on MacOS 14.4.1

#include
Serial.println(__cplusplus);

gives : 201103

So it looks like the compiler for the ATSAME51 32-bit Cortex M4 uses C++11 ??!!

Anybody has an idea why ?

Is there a way to compile with C++20 ?

There was a discussion not too long ago about compiler versions.

It takes a hell of a lot of time to thoroughly test a board package against a new compiler version. I think that the developers of board packages feel that the advantages (if any) are not outweighing the efforts and risks.

1 Like

the different Arduino IDE's are still using C++11.

I remember a post where it was discussed that you can modify the compilation instructions to use C++17 (if I remember correctly)

EDIT: that was the post

note @ptillisch remark:

Clear answer. Thanks !

Will stick to C++11.

For what it is worth, in the last release of Teensyduino (current version in board manager) the Teensy boards (PJRC) were updated from C++14 (If I remember correctly) to C++17 over a reasonably long beta cycle. During that beta cycle there were several things that needed to be updated:

Some were simply updates to remove compiler warnings. Side note: I wish more developers worked to eliminating compiler warnings. Often times we get anesthetized by constantly seeing
pages of warnings, that we miss seeing the important ones.

But there were several other changes that were needed to fix things that no longer worked. Things like object constructors which were declared constexpr, that worked as desired on c++14 but worked differently with the c++17.
In particular the goal was to have the class completely configured/initialized without needing any code needed to be run... i.e. the object is not in the list of objects who need to be called at startup time...

Why that was important, was things like suppose: you have another class whose constructor refers to these classes, like for a hardware Serial port, or a Wire object or the like. And for example, calls Wire.begin(...) as part of it's constructor, but the Wire class had not been initialized, and for example does not have it's const pointer to it's hardware details set...

The code was working fine with 14, but 17, changed the rules (or some implementation about some gray area changed) in regard to this.

In this case, it had to do with assigning a const pointer in the constructor initializer list
Which in the C14 in some case it had simply assigned the value to the memory image as desired, but with C17 it changed and run time code was called... Had to do with how things were cast in the constructor. Fixed by using data type uintptr_t...

The exact details are not that important to this discussion.

But the main thing is, that simply changing a setting such as this, can end up creating
seemingly random bugs like crashes, that appear to be completely random. In the above like case
you would only run into it, if your constructor happened to reference some other object which expects that all of their critical data was setup, and the referring object happens to be in the list of objects (stuff that __libc_init_array() ) before the object it refers to.

So please don't go globally changing, settings such as this, without going through some form of large-scale testing and some form of beta cycle... But as individual users, who desire such changes, go for it! If enough people request such an update and there is a lot of positive outcomes it probably makes it more likely that different boards will update to the newer stuff stuff.

1 Like

Doesn’t c++ state you should not depend on the order in which constructors are called? That’s why we add begin methods

1 Like

Maybe, that is how I typically code things. Unfortunately, there is a lot of code out there, that does stuff in their constructors...

And again this is only one example that I remembered on things that changed between different c++ version changes

I think this specific constrait has been there a long time
(But yes too many libraries do stuff in the constructor they should not, like calling pinMode)

1 Like

Hi, could you please give me a link where I can read more about what not to do in ctor with Arduino, like calling pinMode()

There is no link that I know of besides the c++ documentation

Just don’t do stuff in there that

  • depends on the order of constructors’ call
  • rely on the assumption that the MCU is fully setup and functional (eg pimMode can be undone later on, Serial is not activated nor even configured…)
1 Like

This site is a good reference for C++ and C. I was shocked at how much code I write that has problems with order of evaluation.

This has examples and rules for initialization of base and derived classes.

Here are 20 order of evaluation rules for expressions.

It would be nice if all board support packages had at least C++17 but I understand why this won't happen.

Here is a example of the problem this causes for me. Should I post libraries that depend on C++17 or struggle to provide a version with reduced features for other boards.

The simple include file, VaPrint.h, wraps classes derived from Print adds variadic print and printf. Also it supports variadic macros that are nice for debug.

#include "VaPrint.h"
VaPrint vp(Serial);

// Demo of Variadic debug macro.
#define ENABLE_DBG_MSG 1
#define DBG_FILE "VaPrint.ino"

#if ENABLE_DBG_MSG
#define DBG_MSG(...) vp.println(F(DBG_FILE), ':', __LINE__, ' ', ##__VA_ARGS__)
#else  // ENABLE_DBG_MSG
#define DBG_MSG(...)
#endif  // ENABLE_DBG_MSG

void setup() {
  vp.pr.begin(9600);
  while (!vp.pr) {}
  DBG_MSG("start test: " , millis(), " ms");
  String abc("abc, ");
  vp.println(abc, 123, ", PI: ", Num(PI, 10), ", hex: 0x", Num(1234, HEX));
  vp.pr.write("All public members of Serial can be used.\n");
  vp.printf("printf PI: %.10f\n", PI);
  DBG_MSG("end test: " , millis(), " ms");
}
void loop() {}

Prints this on an Uno R4. It won't compile on Uno R3.

VaPrint.ino:17 start test: 749 ms
abc, 123, PI: 3.1415926536, hex: 0x4D2
All public members of Serial can be used.
printf PI: 3.1415926536
VaPrint.ino:22 end test: 751 ms

Here is VaPrint.h

#pragma once
template <typename T>
class Num : public Printable {
 public:
  Num(T n, int p) : n_(n), p_(p) {}
  size_t printTo(Print& pr) const { return pr.print(n_, p_); }
  T n_;
  int p_;
};

template <class C>
class VaPrint {
 public:
  VaPrint(C& p) : pr(p) {}
  C& pr;

  size_t print(bool b) { return print(b ? F("true") : F("false")); }
  size_t print() { return 0; }  // terminate Variadic templates
 
  template <typename T>
  size_t print(T arg) {
    return pr.print(arg);
  }
  template <typename T, typename... Types>
  size_t print(T var1, Types... var2) {
    size_t n = print(var1);
    return n + print(var2...);
  }
  template <typename... Types>
  size_t println(Types... params) {
    size_t n = print(params...);
    return n + print("\r\n");
  }
  int printf(const char* fmt, ...)  __attribute__ ((format (printf, 2, 3))) {
    char buf[64];
    va_list args;
    va_start(args, fmt);
    int rtn = vsnprintf(buf, sizeof(buf), fmt, args);
    va_end(args);
    if (rtn > 0 && rtn < sizeof(buf)) {
      return pr.write(buf, rtn);
    }
    return -1;  // To do - add dynamic memory option.
  }
};
1 Like

Thank you. I knew about those generic rules. But being new to Arduino and when @J-M-L said

I thought there are some Arduino specific exceptions/ways of doing things in ctors.

nope - just bad programming :slight_smile:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.