www.mikrocontroller.net

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


Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht 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:

/**
 @brief macros for automatically storing string constant in program memory
*/
#define lcd_puts_P(__s)         lcd_puts_p(PSTR(__s))

#define ERROR_SD_READ "Error SD_read"





  if( 0 != getSDinfos(&sdInfo) ){
    lcd_init(LCD_DISP_ON);
    lcd_puts_P( ERROR_SD_READ );
    HALT;
  }


  if(0 != SD_readSingleBlock(sdInfo.rootDirSector, (uint8*)s_logBuf,8)) /* temporary use logging buffer */
  {
    lcd_init(LCD_DISP_ON);
    lcd_puts_P( ERROR_SD_READ );
    HALT;
  }


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?

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

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

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mach eine const Variable daraus und kein Define.

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PROGMEM char ERROR_SD_READ[] = "Error SD_read";
  :
    lcd_puts_p( ERROR_SD_READ );

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Worin liegt das Problem, den String nur einmal zu definieren, ihn aber 
mehrmals zu verwenden?
char ERROR_SD_READ[] PROGMEM = "Error SD_read";
...
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.

Autor: Stefan Ernst (sternst)
Datum:

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

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich
const char STR1[] = "Hallo";
const char STR2[] = "Hallo";
mit avr-gcc 4.3.2 übersetze gibt das
.global  STR1
  .data
  .type  STR1, @object
  .size  STR1, 6
STR1:
  .string  "Hallo"
.global  STR2
  .type  STR2, @object
  .size  STR2, 6
STR2:
  .string  "Hallo"
.global __do_copy_data

Autor: Stefan Ernst (sternst)
Datum:

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

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.
>
>
> Func1("Hallo");
> Func2("Hallo");
> 
> An beide Funktionen wird der selbe Pointer übergeben.

Du hast aber keine Literale:
#include <avr/pgmspace.h>

extern void foo1 (const char*);
extern void foo2 (const char*);

void foo (void)
{
    foo1 (PSTR ("hallo"));
    foo2 (PSTR ("hallo"));
}

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

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

Johann

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.