c: gcc/avr gleiche/ungleiche varianten of string declarartion

OP (Firma: @home) #5927532
hi,
variante 1 und variante 2 sollten eigentlich gleichen code erzeugen ... 
tun sie aber nicht bzgl. ram allocation, bei variante 2 liegt die string 
copy im ram, wie kann ich das vermeiden?

mt
1
variante 1:
2
PROGMEM const char unit0[] = "uSv/h";
3
PROGMEM const char unit1[] = "uR/h";
4
PROGMEM const char unit2[] = "mR/h";
5
PROGMEM PGM_P const unitTable[] = {unit0, unit1, unit2};
6

7
variante 2:
8
enum {UNIT_uSv, UNIT_uR, UNIT_mR};
9
PROGMEM PGM_P const unitTable[] = {
10
  [UNIT_uSv] = "uSv/h",
11
  [UNIT_uR] = "uR/h",
12
  [UNIT_mR] = "mR/h",
13
};
Persönliche Seite #5927608
Variante 2 ist mit progmem nicht darstellbar.

PSTR ist an der Stelle syntaktisch nicht möglich.

Was geht:

Variante A
1
#include <avr/pgmspace.h>
2

3
const char unitTable[][6] PROGMEM =
4
{
5
  "uSv/h", "uR/h", "mR/h"
6
};
Allerdings ist das dann kein Array von const char*.  Für ein Array von 
const char* braucht man Strings in progmem wie in deiner Variante 1 oder 
man verwendet __flash mit Compound Literals:

Variante B
1
#define FSTR(X) (const __flash char[]) { X }
2

3
const __flash char* const __flash unitTable[] =
4
{
5
  FSTR ("uSv/h"), FSTR ("uR/h"), FSTR ("mR/h")
6
};
progmem ist ein Attribut und bezieht sich immer auf das definierte 
Objekt.  __flash ist ein Qualifier (wie z.B. const oder volatile) und 
kann sich auch auf ein Pointer-Target beziehen.  Mit __flash geht 
natürlich auch das Analogon von Variante A:

Variante C
1
const __flash char unitTable[][6] =
2
{
3
  "uSv/h", "uR/h", "mR/h"
4
};

Nachteil der Varianten A und C ist, dass man die Maximallänge der 
beteiligten Strings kennen muss, und dass man Verschnitt hat, wenn viele 
Strings unterschiedlicher Längen auftreten.  Außerdem muss mit der 
Stringlänge multipliziert werden, was teuer ist, wenn der µC keine MUL 
Instruktion kennt.

Bei Variante B hat man hingegen Verschnitt durch die zusätzlich zu 
speichernden String-Adressen, und man hat eine Indirektion mehr.  Dafür 
braucht es nur eine einfache Multiplikation mit 2:
1
char get_first_B (const __flash char* const __flash strings[], uint8_t index)
2
{
3
    return strings[index][0];
4
}
5

6
char get_first_C (const __flash char strings[][6], uint8_t index)
7
{
8
    return strings[index][0];
9
}
compiliert zu:
1
get_first_B:
2
  mov r30,r22
3
  ldi r31,0
4
  lsl r30
5
  rol r31
6
  add r30,r24
7
  adc r31,r25
8
  lpm r0,Z+
9
  lpm r31,Z
10
  mov r30,r0
11
  lpm r24,Z
12
  ret
13

14
get_first_C:
15
  ldi r18,lo8(6)
16
  mul r22,r18
17
  add r24,r0
18
  adc r25,r1
19
  clr __zero_reg__
20
  movw r30,r24
21
  lpm r24,Z
22
  ret

Vorteil von __flash ist, dass man die hässlichen pgm_read_xxx nicht mehr 
braucht und dass es einfacher ist, an Situationen anzupassen, in denen 
__flash nicht verfügbar oder ungünstig ist:
1
#if !defined(__FLASH) || defined (__AVR_PM_BASE_ADDRESS__)
2
#define __flash // empty
3
#endif
Nachteil ist, dass es nicht in C++ verfügbar ist (kann man wahlweise 
auch als Nachteil von C++ ansehen ;-))

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 7 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.