|
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.
[Prev in Thread] | Current Thread | [Next in Thread] |