class members in PROGMEM

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would like to have const class members located in flash.

The following contrived example compiles but the class members "name" are in RAM even though the PROGMEM attribute is attached.

can anyone suggest a solution?

Thanks

#include 
#include 


template class aTemplate
{
	public:
		T a;
		char buf[SIZE];
		const char * name PROGMEM;
		aTemplate(const char * p)
		{
			name = p;
		};
};

class aClass
{
	public:
	int a;
	char buf[10];
	const char * name PROGMEM;
	aClass(const char * p)
	{
		name = p;
	};
};

const char aString[] PROGMEM = "A String for Classes"; 

aTemplate t(aString);
aClass c(aString);

int main(void)
{
	
    t.a = 100;
	t.buf[0]= 1;
	t.buf[1]= 2;
	
	c.a=99;
	
    {
        //TODO:: Please write your application code 
    }
}

regards
Greg

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When I compile your code sample I get 2 warnings:

'__progmem__' attribute ignored [-Wattributes]

referring to the 2 lines where PROGMEM comes after name.

If I put PROGMEM before name i.e.

const char * PROGMEM name; 

the warnings disappear.

I'm a bit rusty on C++ but I would have thought that the PROGMEM attribute would need to be applied to any declaration before its name and not after it?

Not sure if this helps but just thought I'd mention it anyways.

Cheers
Wysi

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am guessing form the lack of response from the "old hands" that I have asked something pretty silly.

any feedback would be appreciated.

regards
Greg

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've not dealt with this for years... but... If memory serves, there is no support for storage of sub-variables within compound data types ( classes ). Actually, that would make sense because it would require spreading the defined datatype across multiple memory spaces ( in this case flash and RAM ). So, the question is, why do you need to store the pointer to the string in flash ( yes, it would save a bit of space... )... the string itself is being properly stored in PROGMEM isn't it?

Martin Jay McKee

As with most things in engineering, the answer is an unabashed, "It depends."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't pretend to understand the C++ but it is certainly the case that PROGMEM (__attribute__((progmem))) can only be applied to global or statics. So if you made the class member static I imagine it might work but I guess that defeats the purpose of everything being encapsulated in the class.

#include 
#include 

const char global[] PROGMEM = "test1";

int main(void) {
	const static char static1[] PROGMEM = "test2";
	const char auto1[] PROGMEM = "test3"; //Warning 1 '__progmem__' attribute ignored [-Wattributes]	
}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can an individual member of a struct in C be allocated to PROGMEM? I do not think so, but am not sure.

If an individual member in a struct can not be allocated to PROGMEM, then I would hold little hope for a member of a class.

I would have somewhat bigger hopes for a static member, as Cliff speculates.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#include 

struct {
	int n;
	const char foo[20] PROGMEM; // Warning 1 '__progmem__' attribute ignored [-Wattributes]
} mystruct = {
	12345,
	"hello world"
};

int main(void) {
}

I also tried replacing "PROGMEM" with __flash and got:

Error	1	'__flash' specified for structure field 'foo'	C:\Documents and Settings\asl\My Documents\Atmel Studio\ledblink\ledblink\ledblink.c	5	2	ledblink

BTW obviously this works:

const struct {
	int n;
	const char foo[20];
} mystruct PROGMEM  = {
	12345,
	"hello world"
};

But the C++ equivalent of that would be putting a whole class into flash.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Guys,
Thanks for all the feedback.

it seems the conclusion is that data in a struct or class cannot be split across different memory spaces. :(

interesting to me that I did not get a warning. I am using 6.1beta with the back-end patch applied.

one poster did report a warning.

regards
Greg

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

gregd99 wrote:
Guys,
Thanks for all the feedback.

it seems the conclusion is that data in a struct or class cannot be split across different memory spaces. :(

You emote as if this is a big disappointment to you. How exactly did you expect pointer dereferencing to work (as in, "myClassPtr->aMember"), if there were no guarantee that all the members of a class/struct are consecutively allocated in one block of memory (and therefore reachable via fixed offsets from a single instance pointer)? Or the ability to dynamically create/construct instances of a class? Or the ability to have arrays of objects?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

all the items you raise are good points.

indeed I would like the option to have pointers in flash (same as vtabs :D )

The compiler does many impressive things that i don't understand. I deduce from your comments as well as those above that the flash members would be a bridge too far.

regards
Greg

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Levenkay wrote:
How exactly did you expect pointer dereferencing to work (as in, "myClassPtr->aMember"), if there were no guarantee that all the members of a class/struct are consecutively allocated in one block of memory ?
As Clawson earlier posted, static class data members are not accessed through the "this" pointer.

clawson wrote:
So if you made the class member static I imagine it might work but I guess that defeats the purpose of everything being encapsulated in the class.
No, the static members are still members of the class and have class scope.

Actually class member functions are not accessed through a pointer either, although the way you call them seems to imply they are accessed through a pointer.

Here is a goofy little program that illustrates this. Main constructs a class with static data members. Then it creates a pointer to the class. Then it sets the pointer value to zero, or any number. Then it calls a function in the class using this bogus pointer. It works every time.

// this is main.cpp

#include "test_statics_class.h"

int main (void)   {
   new Test_statics_class;

   Test_statics_class* test_statics_class_p = 0;   // set class pointer to zero, or whatever you want.

   int sum = test_statics_class_p->Add_them_up();  // access class through this bogus pointer.
   }
// This is test_statics_class.h

class Test_statics_class   {
public:
   Test_statics_class()   {
      a = 1;
      b = 2;
      }

   static int a;
   static int b;

   int Add_them_up()   {
      return a + b;
      }
   };
// this is test_statics_class.cpp

#include "test_statics_class.h"

int Test_statics_class::a;
int Test_statics_class::b;
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

No, the static members are still members of the class and have class scope.

Yes I know that but my point was that presumably you made it a member variable because you wanted a unique copy per instantiation rather than a single static one across them all.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The OP does seem to use the member variable in a way that should be unique to each instantiation, however static variables find plenty of use. They are, after all, just scope limited global variables. Anytime a class will need to access a shared resource ( a communication channel, a common buffer, etc. ) static variables make sense. They're also handy for implementing the singleton pattern ( which only allows for a single instantiation of a class -- always accessed by reference ( or pointer ).

Martin Jay McKee

As with most things in engineering, the answer is an unabashed, "It depends."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
It works every time.

But you are still relying on something that might or might not work, depending on compiler, compiler version, compiler options, phase of the moon and more.

And when you accidentally make the mistake of accessing a non-static member variable in a member function you are in big trouble.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
Quote:
It works every time.

But you are still relying on something that might or might not work, depending on compiler, compiler version, compiler options, phase of the moon and more..
That could be, but I've never seen it fail.
Quote:
And when you accidentally make the mistake of accessing a non-static member variable in a member function you are in big trouble.
Exactly so. As I said, this is a goofy example to demonstrate that the "this" pointer is not used for class member functions and static member data.

When I was learning C++ I accidentally used a null pointer to access a class member function and was shocked to find it did correctly call the function. When that function tried to access a non-static data member it caused an addressing exception on the PC.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The original idea I had was to have per instance pointers to external data structures. Since the pointers would be const I wanted to put them in flash rather than ram.

it seems that this is not possible.

the discussion on statics is interesting but this is a different application.

regards
Greg

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I use some static data when I have a linked list of classes. In addition to the linked list I have a pointer to the first member and probably a pointer to the last member. I make these pointers static members of the class.