Do accessors increase PROGMEM consumption?

There were discussions about the benefits of accessor functions [1], [2], [3]. Apart from religious aspects of the discussion, the statement that accessors cause runtime costs appeared quite often.

This is something that is hard to get out of the heads of programmers coming from other languages that do not feature function inlining, C programmers included. But C++ has its own rules. Inline functions can actually disappear from the assembly and thus from our precious PROGMEM.

C++'s inline keyword asks the compiler to replace the invocation of a function with the function body. The compile can refuse this request when the replacement does not make sense, e.g. for performance reasons. When an inlined function is sufficiently short, it will almost always be inlined. When it comes to inlined accessors this means that, e.g. for a getter an assignment of the return value of a function is replaced by the returned value, typically a member.

The following short program may be used to investigate the matter (on x86 without modifications). It can be compiled with or without defining the preprocessor macro HAVE_CLASS, which leads to two equivalent programs (except from the value that is output). One of the two uses a plain old struct, the other a C++ class that features full encapsulation.

#include <iostream>

// #define HAVE_CLASS

#ifdef HAVE_CLASS

class Foo {
   public:
      void setMember(int value) {
         member_ = value;
      }
      
      int getMember() const {
         return member_;
      }
   private:
      int member_;
};

#else

struct Foo {
   int member_;
};

#endif

int main() {

   Foo foo;

   #ifdef HAVE_CLASS
   foo.setMember(42);
   std::cout << "Member is " << foo.getMember() << std::endl;
   #else
   foo.member_ = 37;
   std::cout << "Member is " << foo.member_ << std::endl;
   #endif
}   

When the two versions of the program are compiled without any optimizations enabled, the binary size of the version that uses the class is slightly larger. When compiled with -Os or -O3, both versions of the program have the exact same size. Thus, we can conclude that inlined accessors do not have an impact on PROGMEM requirements, as the firmware is compiled passing -Os to the compiler.

When compiled with gcc 5.4 on an x86 64 version, this test results in the following file sizes.

-rwxr-x--- 1 noseglasses noseglasses 9416 Dez 16 18:11 class_test_no_optimization*
-rwxr-x--- 1 noseglasses noseglasses 9160 Dez 16 18:12 class_test_O3*
-rwxr-x--- 1 noseglasses noseglasses 9136 Dez 16 18:11 class_test_Os*
-rwxr-x--- 1 noseglasses noseglasses 9272 Dez 16 18:11 struct_test_no_optimization*
-rwxr-x--- 1 noseglasses noseglasses 9160 Dez 16 18:12 struct_test_O3*
-rwxr-x--- 1 noseglasses noseglasses 9136 Dez 16 18:12 struct_test_Os*

It is up to the reader to add the respective data structures to the firmware and test it with avr-gcc. The result will, however, be the same.

1 Like