avr-libc-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-libc-dev] PSTR() and duplicate strings


From: David Brown
Subject: Re: [avr-libc-dev] PSTR() and duplicate strings
Date: Tue, 05 Apr 2011 10:09:00 +0200
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.15) Gecko/20110303 Lightning/1.0b2 Thunderbird/3.1.9

On 04/04/2011 23:11, Benoît Ryder wrote:
Hi,

I have a question about the use of PSTR(), optimizations and objects
located in program space.
With optimizations enabled the compiler detect several occurrences of
identical constant strings to store them only once in the binary.
However, when using PSTR(), these optimizations are not made and the
string is duplicated.

For instance, using the following code, the string "123" is stored
only once in the resulting binary:
   fprintf(stdout, "123");
   fprintf(stdout, "123");

With the following code, the string "123" is stored twice, resulting
in a 4-byte overhead.
   fprintf(stdout, PSTR("123"));
   fprintf(stdout, PSTR("123"));

This does not matter much for small strings but the overhead can
become pretty large with numerous large strings (e.g. verbose log
messages).

There are two definitions of PSTR(). A "fake" definition intended for Doxygen:
   #define PSTR(s) ((const PROGMEM char *)(s))
And the "real one":
   #define PSTR(s) (__extension__({static char __c[] PROGMEM = (s);&__c[0];}))

When using the fake version, duplicates are optimized and strings are
located in the flash ROM, as excepted. The real version prevent
optimizations to be made (which is an expected behavior, according to
the definition code).
So, my question is: is there an actual difference between the two
definitions of PSTR() (besides the fact that pointer addresses will
differ)? May I safely switch to the fake definition to benefit from
the optimizations?

Thanks!

Benoît Ryder


There is a big difference between the real and fake versions. The fake version allocates an ordinary string, which is therefore put in data (ram). The "PROGMEM" in the definition is just for documentation. The real version makes a static array of chars in flash, and returns a pointer to that.

The problem here is the way literal strings work in C (or at least gcc). The string itself is created within the .data section, like a normal variable. So using the "fake" version, you get the string in ram - which is probably not what you want (ram space being at more of a premium than flash space).

The "real" version of the macro uses an array of chars, rather than a string literal, to get the text itself entirely within flash. Unfortunately, because we are no longer dealing with strings as such, the compiler can't merge them in the same way.

There is a "-fmerge-all-constants" flag - it is possible that this will give you the merging you want (though it doesn't seem to have the effect when I tested on a single file).

As far as I understand it, work is currently being done towards using separate memory spaces for flash rather than the PROGMEM system (now that the latest C standards define such memory spaces). It may be that this would allow a more "natural" syntax for strings in flash, and also allow such merging to take place.

See also these links:

<http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21018#c6>
<http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43746>

In other words, this is been filed as an enhancement request rather than a bug.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]