Forum: Mikrocontroller und Digitale Elektronik [AVR] compiler optimiert strings nicht richtig


von Vlad T. (vlad_tepesch)


Lesenswert?

Hi,
Ich hab ein Problem/Frage:

Ich hab  in meinem Code mehrere Stellen, wo ich Meldungen ausgebe.
es gibt merhere Meldungen, die den selben Text enthalten.

Die strings sind komplett identisch (selbes #define), jedoch legt der 
compiler die 2 mal an, anstatt sie einmal anzulegen und den pointer auf 
das selbe zeigen zu lassen.

Die zeichenketten selbst liegen im program memory, können also nicht 
verändert werden.

beispiel:
1
/**
2
 @brief macros for automatically storing string constant in program memory
3
*/
4
#define lcd_puts_P(__s)         lcd_puts_p(PSTR(__s))
5
6
#define ERROR_SD_READ "Error SD_read"
7
8
9
10
11
12
  if( 0 != getSDinfos(&sdInfo) ){
13
    lcd_init(LCD_DISP_ON);
14
    lcd_puts_P( ERROR_SD_READ );
15
    HALT;
16
  }
17
18
19
  if(0 != SD_readSingleBlock(sdInfo.rootDirSector, (uint8*)s_logBuf,8)) /* temporary use logging buffer */
20
  {
21
    lcd_init(LCD_DISP_ON);
22
    lcd_puts_P( ERROR_SD_READ );
23
    HALT;
24
  }

wenn ich jetzt ins list-file oder ins elf-file schaue, gibts den string 
"Error SD_read" mehrmals.

Was muss ich tun, damit der string nur einmal eingebunden wird?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Was muss ich tun, damit der string nur einmal eingebunden wird?
Mach eine globale Variable mit dem String:
1
 char ERROR_SD_READ[] = "Error SD_read";
2
  :
3
    lcd_puts_P( ERROR_SD_READ );
4
  :

von Gast (Gast)


Lesenswert?

mach eine const Variable daraus und kein Define.

von Vlad T. (vlad_tepesch)


Lesenswert?

das macht keinen Sinn.
dann brauch der string sowohl daten, als auch programmspeicher + die 
Pointervariable
ich suche eher einen Compilerswitch oder trick, der ihn zwingt doppelte 
strings nur einmal anzulegen.

von holger (Gast)


Lesenswert?

PROGMEM char ERROR_SD_READ[] = "Error SD_read";
  :
    lcd_puts_p( ERROR_SD_READ );

von gast (Gast)


Lesenswert?

>ich suche eher einen Compilerswitch oder trick, der ihn zwingt doppelte
>strings nur einmal anzulegen.

Ein 'guter' Compiler macht das von alleine. Zur Not auf 'size' 
optimieren lassen.

von Vlad T. (vlad_tepesch)


Lesenswert?

>Ein 'guter' Compiler macht das von alleine. Zur Not auf 'size'
>optimieren lassen.

hätt ich ja auch gedacht

ist halt ein gcc
duck und weg

und auf size optimieren ist schon an.

aber holgers variante scheint zu funktionieren.

Trotzdem hätt ich lieber ne Variante, wo das der compiler automatisch 
macht.

von Stefan E. (sternst)


Lesenswert?

Worin liegt das Problem, den String nur einmal zu definieren, ihn aber 
mehrmals zu verwenden?
1
char ERROR_SD_READ[] PROGMEM = "Error SD_read";
2
...
3
lcd_puts_P( ERROR_SD_READ );

Und ja, der String ist dann nur einmal im Speicher (Flash).
Und nein, das verbraucht keinen zusätzlichen Platz für irgendwelche 
Pointer.

von Stefan E. (sternst)


Lesenswert?

Ach übrigens: das funktioniert wegen dem zusätzlichen Attribut nicht. 
"Normale" Strings (also in RAM) legt er automatisch zusammen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jeder String ist ein eigenständiges Objekt. Ich wüsst nicht wie gcc das 
optimieren können sollte.

Das ist eine Aufgabe für ld. Er kann Strings mixen; dazu setzt man an 
der entsprechenden Section das S-Flag (mergeable strings).

Dazu muss jeder String in seine eigene Input-Section.

Johann

von Stefan E. (sternst)


Lesenswert?

Johann L. schrieb:
> Jeder String ist ein eigenständiges Objekt. Ich wüsst nicht wie gcc das
> optimieren können sollte.

Es geht um Stringliterale gleichen Inhalts. Hier wird normalerweise der 
eigentliche String nur einmal angelegt. Das Section-Attribut hebelt das 
aber irgendwie aus, und der String wird mehrfach angelegt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wenn ich
1
const char STR1[] = "Hallo";
2
const char STR2[] = "Hallo";
mit avr-gcc 4.3.2 übersetze gibt das
1
.global  STR1
2
  .data
3
  .type  STR1, @object
4
  .size  STR1, 6
5
STR1:
6
  .string  "Hallo"
7
.global  STR2
8
  .type  STR2, @object
9
  .size  STR2, 6
10
STR2:
11
  .string  "Hallo"
12
.global __do_copy_data

von Stefan E. (sternst)


Lesenswert?

Was willst du mir damit sagen? Natürlich sind STR1 und STR2 zwei 
unterschiedliche Objekte. Es geht nicht um Variablen, sondern die 
Literale.
1
Func1("Hallo");
2
Func2("Hallo");
An beide Funktionen wird der selbe Pointer übergeben.

von Vlad T. (vlad_tepesch)


Lesenswert?

genau nur scheint er acr-gcc das nicht hinzubekommen, wenn man die 
Strings in den Program-memory stecken will.
Dann legt er jeden extra an.

Aber Holgers lösung funktioniert.
Ist sowiso sauberer die messages an einer Stelle zu halten.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stefan Ernst schrieb:
> Was willst du mir damit sagen? Natürlich sind STR1 und STR2 zwei
> unterschiedliche Objekte. Es geht nicht um Variablen, sondern die
> Literale.
>
>
1
> Func1("Hallo");
2
> Func2("Hallo");
3
>
> An beide Funktionen wird der selbe Pointer übergeben.

Du hast aber keine Literale:
1
#include <avr/pgmspace.h>
2
3
extern void foo1 (const char*);
4
extern void foo2 (const char*);
5
6
void foo (void)
7
{
8
    foo1 (PSTR ("hallo"));
9
    foo2 (PSTR ("hallo"));
10
}

Wird expandiert zu
1
void foo (void)
2
{
3
    foo1 ((__extension__({static char __c[] __attribute__((__progmem__)) = ("hallo"); &__c[0];})));
4
    foo2 ((__extension__({static char __c[] __attribute__((__progmem__)) = ("hallo"); &__c[0];})));
5
}

und damit gibt es zwei __c-Objekte, eines für jedes "hallo".

Johann

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.