AVR Freaks

AVR GCC forum - C++ warning with PROGMEM (4.2.2)

MegaTorr - Dec 02, 2007 - 07:43 PM
Post subject: C++ warning with PROGMEM (4.2.2)
Recompiling a project with avr-gcc 4.2.2 leads to the message
Quote:
warning: only initialized variables can be placed into program memory area
. Both of the following variables lead to the same problem:

Code:
#include <stdint.h>
#include <avr/pgmspace.h>


typedef struct {
  uint8_t reg_, addr_;
} init_table_t;

init_table_t initTable[] PROGMEM = {
    { 1, 17 },
    { 7, 33 },
};

char aString[] __attribute__((progmem)) = "initialized or not, that's the question";


Anybody know what's going on here?
Jepael - Dec 02, 2007 - 08:10 PM
Post subject: RE: C++ warning with PROGMEM (4.2.2)
At least the initTable has an extra comma there before };

- Jani
JohanEkdahl - Dec 02, 2007 - 08:35 PM
Post subject: RE: C++ warning with PROGMEM (4.2.2)
Quote:

the initTable has an extra comma there before };


Which actually is allowed in C (IIRC).
MegaTorr - Dec 02, 2007 - 09:10 PM
Post subject: RE: C++ warning with PROGMEM (4.2.2)
the comma is allowed (like an extra ; ).
I should also mention that the code compiles fine if compiled as C code, and the C++ version was OK for avr-gcc 4.1.1.
JohanEkdahl - Dec 02, 2007 - 09:23 PM
Post subject: RE: C++ warning with PROGMEM (4.2.2)
Quote:
the C++ version was OK for avr-gcc 4.1.1

Time to look for, or report, a regression bug?
Tuomas - Dec 03, 2007 - 12:03 AM
Post subject:
I have seen the same warning. The most annoying thing is that every occurence of printf_P(PSTR("...")) emits this warning.

Here is a testcase and its output when using avr-c++. Notice that only one of the two initializations produces the warning. If I feed this code trough the C compiler no warnings are emitted and the resulting assembly code is identical.
Code:
#include <avr/io.h>
#include <avr/pgmspace.h>

const prog_char p_str2[] = "321";

int __attribute__((naked)) main()
{
   PGM_P p_str = PSTR("123"); //main.cpp:8: warning: ...

   PORTA = pgm_read_byte(&p_str[0]);
   PORTB = pgm_read_byte(&p_str2[0]);

   return 0;
}
Code:
[tuomas@blackbox var_test]$ make
avr-gcc -I. -g  -mmcu=atmega32 -Os -fpack-struct -fshort-enums -funsigned-bitfields -funsigned-char -Wall -Wa,-ahlms= -fno-exceptions -fcheck-new -Wa,-ahlms=main.lst -c main.cpp -o main.o
main.cpp: In function 'int main()':
main.cpp:8: warning: only initialized variables can be placed into program memory area
avr-gcc -o myproject.out  main.o    -Wl,-Map,myproject.out.map -mmcu=atmega32 -lm
[tuomas@blackbox var_test]$


For this second example I don't know a workaround that wouldn't produce any warnings.
Code:
#include <avr/io.h>
#include <avr/pgmspace.h>

const prog_char str[] = "123";
const prog_char* p_str PROGMEM = str; //warning

int __attribute__((naked)) main()
{
   PGM_P ptr;

   ptr = (prog_char*)pgm_read_word(&p_str);
   PORTA = pgm_read_byte(ptr);

   return 0;
}

MegaTorr - Dec 23, 2007 - 05:49 AM
Post subject:
Using the new version (gcc-4.2.2, avr-libc-1.6.1) I've done some checking and found a solution, or work around, I'm not sure which one.

PSTR is defined as (pgmspace.h):
Code:
# define PSTR(s) (__extension__({static char __c[] PROGMEM = (s); &__c[0];}))
If I change the definition to
Code:
# define PSTR(s) (__extension__({static prog_char __c[] = (s); &__c[0];}))
g++ is happy as well. I'm not sure if this is a g++ issue or if g++ just got a little more standards compliant and it is an avr-libc issue.

Markus
DosMan - Jan 06, 2008 - 04:04 AM
Post subject:
I have just switched to WinAVR 20071221. I now get this compiler warning on all initialized variables I've defined with PROGMEM, which includes many structures and arrays. The work-around of changing type from char to prog_char can't be applied to structures.

It appears that I do get all the correct results, but it's startling to see a new WinAVR released with such an obvious (if minor) bug.
oloftangrot - Jan 06, 2008 - 08:51 PM
Post subject:
I am on to something but I don't know what.

Observation 1:
Code:

prog_int32_t rt; // no warning

int PROGMEM rt2; // warning

The difference is that prog_int32 is typedefed.

Observation 2:
Code:

class C
{
  void method( void );
} PROGMEM cObj1; // No warning.

C PROGMEM cObj2; // Warning

A class definition is treated as a typedef sometimes.

Observervation 3:
Code:

#if 1 // try 1 or 0
prog_int32_t rt1; // at the same time as
int PROGMEM rt2 = 5; // results in a error...
#else
class C
{
  void method( void );
} PROGMEM cObj1; // at the same time as
int PROGMEM rt2 = 5; // results in a error...
#endif

... error: rt2 causes a section type conflict.

Cheers

Olof
stu_san - Jan 07, 2008 - 05:19 PM
Post subject:
Tuomas wrote:
Code:
const prog_char str[] = "123";
const prog_char* p_str PROGMEM = str; //warning
You are trying to define a PROGMEM constant using what C thinks is a variable initializer (str). Instead, try:
Code:
const prog_char* p_str PROGMEM = "123";


All PROGMEM constants must be marked as "const", or at least it seems that way to me. I have scads of PROGMEM constants, all defined as const, which compile just fine in WinAVR 20071221. Examples:
Code:
static const char gen_SEMI  [] PROGMEM = "; ";
static const char gen_ZERO  [] PROGMEM = "0";
static const char gen_DOT   [] PROGMEM = ".";
static const char gen_DASH  [] PROGMEM = "-";
static const char gen_SPACE [] PROGMEM = " ";
static const char gen_DUNNO [] PROGMEM = "<unknown>";

. . . in another file, not so very far away...

#define CMD_ERROR_NO_ERROR   0

#define ERROR_TABLE(n) et_ ## n
      
#define ERROR_STRING(n,s) \
   const char et_ ## n [] PROGMEM = s ;

ERROR_STRING( CMD_ERROR_NO_ERROR, "Command succeeded" )
All of the above compile with no errors, no warnings.

Stu
stu_san - Jan 07, 2008 - 05:21 PM
Post subject:
oloftangrot wrote:
Code:

prog_int32_t rt; // no warning

int PROGMEM rt2; // warning
Again, it makes no sense to have a non-const PROGMEM variable. Try the following instead:
Code:
const int PROGMEM rt2 = 5;
Don't forget to give the const a value!

Stu
DosMan - Jan 07, 2008 - 06:57 PM
Post subject:
I suspect those of you not experiencing this problem are using C, not C++. If I cut & paste the line Stu suggests into a C++ program, it gives me the compiler warning.
oloftangrot - Jan 07, 2008 - 08:50 PM
Post subject:
If the keyword "const" is required than why dont I get a warning from:
Code:

prog_int32_t rt;  // const is not a part the the typedef!

???

As I see it the conditions where the warnings are emitted or not emitted from the compiler spurious and misleadning, that is what does not make sense.
Tuomas - Jan 08, 2008 - 12:27 AM
Post subject:
stu_san wrote:
You are trying to define a PROGMEM constant using what C thinks is a variable initializer (str). Instead, try:
Code:
const prog_char* p_str PROGMEM = "123";


Ah, but that was only a simplification I made. What about if I wanted to have an array of flash strings in flash? According to forums PROGMEM tutorial the individual strings must be declared first, and then pointers to them are stored in an array.
Code:
const prog_char str1[] = "123";
const prog_char str2[] = "456";
const prog_char* p_str[] PROGMEM = { str1, str2 };

From that last line GCC C++ compiler (avr-g++ 4.2.2) prints a warning that says:
Code:
warning: only initialized variables can be placed into program memory area

With C compiler the same code is just fine.

EDIT: Added missing square brackets p_str -> p_str[]. Now it looks like the code I tested...
EW - Jan 08, 2008 - 04:20 AM
Post subject:
What if you change the code to this?:

Code:

const prog_char str1[] PROGMEM = "123";
const prog_char str2[] PROGMEM = "456";
const prog_char* p_str PROGMEM = { str1, str2 };


Do you still get a warning with the C++ compiler?
MegaTorr - Jan 08, 2008 - 06:47 AM
Post subject:
yup, you get 3 of them:
Code:

x.cpp:3: warning: only initialized variables can be placed into program memory area
x.cpp:4: warning: only initialized variables can be placed into program memory area
x.cpp:5: warning: only initialized variables can be placed into program memory area
x.cpp:5: error: scalar object 'p_str' requires one element in initializer

Tuomas - Jan 08, 2008 - 12:19 PM
Post subject:
Yes, the result is as MegaTorr posted. In my previous post the square brackets needed in p_str[] were missing for some reason. I edited the post. However, that only gets rid of the show stopping error in MegaTorr's post...
clawson - Jan 08, 2008 - 02:15 PM
Post subject:
I'm late to this party but if the typedef of prog_char is:
Code:
typedef char PROGMEM prog_char;

Then why would one want to use:
Code:
const prog_char str1[] PROGMEM = "123";

That seems to be delivering a lot more "PROGMEM" than is entirely necessary.

Cliff
DosMan - Jan 08, 2008 - 07:57 PM
Post subject:
Neither the (extra) PROGMEM nor the "const" make a difference on the variable initialization. It appears that it is necessary to use typedef to get rid of the warning:

Code:
struct foo
{
   int   i;
};

foo foovar1 PROGMEM = {5};

typedef foo prog_foo PROGMEM;
prog_foo foovar2 = {5};

The definition of foovar1 gets a warning, foovar2 doesn't.
EW - Jan 08, 2008 - 09:05 PM
Post subject:
So it seems there's some weird bug here. I would suggest filling out a bug report on the GCC project.

Note that support for C++ for AVR GCC may be incomplete as there aren't any dedicated people working on it AFAIK.
MegaTorr - Jan 09, 2008 - 08:03 PM
Post subject:
OK, I was preparing everything to report a gcc bug and while I was waiting for the paperwork to complete I went over the documentation again, and this is what I found:

The documentation regarding attributes (function,type,varaiable) is extremely vague and even says on several occasions (in one form or another):
Quote:
... but at present this is not implemented

However, right at the beginning of section "5.26 Attribute Syntax" it says:
Quote:
Some details may vary for C++ and Objective-C. Because of infelicities in the grammar for attributes, some forms described here may not be successfully parsed in all cases.
and later on:
Quote:
There are some problems with the semantics of attributes in C++. For example, there are no manglings for attributes, although they may affect code generation, so problems may arise when attributed types are used in conjunction with templates or overloading. Similarly, `typeid' does not distinguish between types with different attributes. Support for attributes in C++ may be restricted in future to attributes on declarations only, but not on nested declarators.
(italics added by me)

So the documentation says that not all of this might work in C++, and (as I understand it) the only safe way to declare attributes is in the declaration. Following that lead I wrote the following tests:
Code:
int i1 __attribute__((__progmem__)) = 1;
int __attribute__((__progmem__)) i2 = 2;
__attribute__((__progmem__)) int i3 = 3;
extern int i4 __attribute__((__progmem__)); int i4 = 4;
extern int __attribute__((__progmem__)) i5; int i5 = 5;
extern __attribute__((__progmem__)) int i6; int i6 = 6;
typedef int i7_t __attribute__((__progmem__)); i7_t i7 = 7;
typedef int __attribute__((__progmem__)) i8_t; i8_t i8 = 8;
typedef __attribute__((__progmem__)) int i9_t; i9_t i9 = 9;
(sorry about the formatting, but this way the line number corresponds with the version). According to the documentation all 9 variations should be legal for C, and they are. In C++ however the first 3 generate said warnings, whereas the other 6 compile just fine. As a note, the generated code is correct and identical for both, C and C++.

Moving on to strings (which are almost more important in this context than integers) I wrote the equivalent test cases:
Code:
const char s1[] __attribute__((__progmem__)) = "string 1";
const char __attribute__((__progmem__)) s2[] = "string 2";
const __attribute__((__progmem__)) char s3[] = "string 3";
__attribute__((__progmem__)) const char s4[] = "string 4";
extern const char s5[] __attribute__((__progmem__)); const char s5[] = "string 5";
extern const char __attribute__((__progmem__)) s6[]; const char s6[] = "string 6";
extern const __attribute__((__progmem__)) char s7[]; const char s7[] = "string 7";
extern __attribute__((__progmem__)) const char s8[]; const char s8[] = "string 8";
typedef const char s9_t __attribute__((__progmem__)); const s9_t s9[] = "string 9";
typedef const char __attribute__((__progmem__)) s10_t; const s10_t s10[] = "string 10";
typedef const __attribute__((__progmem__)) char s11_t; const s11_t s11[] = "string 11";
typedef __attribute__((__progmem__)) const char s12_t; const s12_t s12[] = "string 12";
Again, all 12 declarations/definitions are legal for C. In C++ however the first 4 generate the warning whereas the latter 8 compile fine. This time, however the generated code differs. The C++ compiler only generates code for the 4 extern declared variables (I currently have no explanation for that)!

The same exercise can be constructed for structs, with the same results. When the initialization goes along with the declaration C++ issues the warning, when declaration and definition/initialization are separated C++ has no issues.

Given the gcc documentation and the results from above I'm not sure if it actually is a gcc bug (it kinda' works like advertised).

I'm currently leaning towards an avr-libc issue. If somebody with more insight than me could let me know which way to go I'll file an issue.

Markus
DosMan - Jan 09, 2008 - 09:12 PM
Post subject:
The documentation you quote has not changed from the previous compiler version. But the compiler has clearly regressed, and it should be reported as such.
MegaTorr - Jan 09, 2008 - 10:12 PM
Post subject:
I'm aware of the old (4.1) documentation, but it didn't have to change. Even the old documentation (4.1) stated that it is not guaranteed to work for C++, although it did. Unfortunately the documentation in this regard is very vague and doesn't state what, and which scenario is supposed to work and which isn't. Strictly speaking, both version (4.1 and 4.2) work as documented.

The way I read it is that it might work, or might not, in both versions. As I understand the documentation it basically says: If it works in C++, good for you, if it doesn't, we told you so.

If I read the documentation wrong, please indicate what I'm missing.

Markus
DosMan - Jan 10, 2008 - 11:23 PM
Post subject:
This is not an issue about whether the attribute works. The attribute does work -- the data is placed in the correct section. This is about some additional logic processing this particular attribute that is producing a bogus warning. The EEMEM attribute, for example, continues to work fine.
MegaTorr - Jan 11, 2008 - 01:44 AM
Post subject:
That is most interesting. Replacing __attribute__((__progmem__)) with __attribute__((__section__(".eeprom")) in the tests above works, except for the typedefs. There I get an error that says:
Quote:
error: section attribute not allowed for ...

and more specifically on some of the structure tests:
Quote:
warning: '__section__' attribute does not apply to types
No wonder the documentation is so vague.

Markus
MegaTorr - Jan 11, 2008 - 02:23 AM
Post subject:
gcc bug #34734
EW - Jan 14, 2008 - 04:03 AM
Post subject:
Thanks. I'm on the CC list.
eldamiani - Feb 19, 2009 - 02:19 PM
Post subject:
If I declare in my class declaration in the header file
Code:
static char text[] PROGMEM;

and then implement in source file
Code:
char text[] PROGMEM = "something";

then I have a warning, but if I implement in source file
Code:
char text[] = "something";//without PROGMEM macro

then everything is ok.

In my case typedef prog_char is not working properly.

Sorry for my not so good english.
Koshchi - Feb 19, 2009 - 03:44 PM
Post subject:
Code:
static char text[] PROGMEM
;
But you are not declaring it static in the source file. Don't you mean:
Code:
extern char text[] PROGMEM;

Quote:
If I declare in my class declaration in the header file

That is not a "class", it is simply a variable.

And what warning are you getting?
DosMan - Feb 19, 2009 - 06:22 PM
Post subject:
It's great news that someone has found a work-around for this erroneous warning. I have dozens of these warnings in my current project, and now there's a way to eliminate some of them. I'm changing variable declarations from this:
Code:
char StrTrue[] PROGMEM = "true";
to this:
Code:
extern char StrTrue[] PROGMEM;
char StrTrue[] = "true";
Many of my warnings are generated from the PSTR() macro and I haven't yet looked to see if it can be rewritten to use the same work-around.
All times are GMT + 1 Hour
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits