Hallo,
möglicherweise scheint meine Frage sehr Trollhaft zu sein. Tatsächlich
ist diese ernst gemeint da ich mich selten mit Attinys beschäftigt habe,
welche sehr begrenzten RAM haben.
1
voiduart_string(constchar*s)
Rufe ich obige Funktion mit einem String auf, wird dieser im Flash
abgelegt und nutzt laut AtmelStudio7 ebenfalls die gleiche Anzahl an
Bytes.
Bei einem Aufruf mit uart_string("T"):
1
Program Memory Usage : 396 bytes 19,3 % Full
2
Data Memory Usage : 62 bytes 48,4 % Full
Bei einem Aufruf mit uart_string("THallo"):
1
Program Memory Usage : 400 bytes 19,5 % Full
2
Data Memory Usage : 66 bytes 51,6 % Full
Warum wird hier der RAM ebenfalls genutzt obwohl das Schlüsselwort const
benutzt wurde? Bin hier gerade etwas überfragt, warum in einer solchen
Situation explizit mit PROGMEM oder __flash gearbeitet werden muss um
dem aus dem weg zu gehen.
BG
Thadeus
Thadeus Kobisky schrieb:> Warum wird hier der RAM ebenfalls genutzt obwohl das Schlüsselwort const> benutzt wurde? Bin hier gerade etwas überfragt, warum in einer solchen> Situation explizit mit PROGMEM oder __flash gearbeitet werden muss um> dem aus dem weg zu gehen.
Weil es keinen durchgehenden Adressraum gibt müssen solche Krücken
benutzt werden.
Der AVR kann eben nicht in gleicher Weise Daten aus dem Flash lesen wie
er sie aus dem Ram lesen würde.
Also entweder die Strings werden im Flash und im Ram abgelegt (also am
Anfang vom Flash ins RAM kopiert) -> alles läuft normal. Oder sie liegen
nur im Flash und du musst spezielle Funktionen nutzen (strcpy_P usw.).
Du hast die Wahl.
Der Unterschied zwischen:
uart_string("T")
und
uart_string("THallo"):
liegt vermutlich darin dass der Compiler für ein einziges Bytes gar
keinen String anlegt, sondern das Byte direkt an der Aufrufstelle
übergibt. D.h. hier fällt das Byte einfach in den Codeteil. Kein RAM
benötigt.
Cyblord -. schrieb:> Der Unterschied zwischen:>> uart_string("T")>> und>> uart_string("THallo"):>> liegt vermutlich darin dass der Compiler für ein einziges Bytes gar> keinen String anlegt, sondern das Byte direkt an der Aufrufstelle> übergibt. D.h. hier fällt das Byte einfach in den Codeteil. Kein RAM> benötigt.
Möglicherweise ein ungünstiges Beispiel.
Zwischen uart_string("THa") und uart_string("THallo") gilt selbiges.
BG
Thadeus
Cyblord -. schrieb:> Weil es keinen durchgehenden Adressraum gibt müssen solche Krücken> benutzt werden.> Der AVR kann eben nicht in gleicher Weise Daten aus dem Flash lesen wie> er sie aus dem Ram lesen würde.> Also entweder die Strings werden im Flash und im Ram abgelegt (also am> Anfang vom Flash ins RAM kopiert) -> alles läuft normal. Oder sie liegen> nur im Flash und du musst spezielle Funktionen nutzen (strcpy_P usw.).> Du hast die Wahl.
Danke für deine Erklärung.
Thadeus Kobisky schrieb:> Zwischen uart_string("THa") und uart_string("THallo") gilt selbiges.
Einfach mal den zugehörigen Assemblercode anschauen dann siehst du was
passiert.
Grundsätzlich gilt das so wie beschrieben. Der Compiler kann und wird
hier aber optimieren wenn möglich. Es ist denkbar dass ein 3 Byte
Parameter sparender direkt im Code abgebildet werden kann als diesen
String tatsächlich an anderer Stelle als String abzulegen.
Cyblord -. schrieb:> du musst spezielle Funktionen nutzen (strcpy_P usw.)
alle str*** Funktionen, nur manchmal bringt str***_P keinen RAM Vorteil
weil diese _P Funktion auch RAM braucht, ich wunderte mich das trotz _P
mehr RAM gebraucht wurde, kann ja jeder selbst probieren, mal als _P
kompilieren mal ohne und je nach Textlänge wird das Ergebnis in used Ram
überraschen
Joachim B. schrieb:> Cyblord -. schrieb:>> du musst spezielle Funktionen nutzen (strcpy_P usw.)>> alle str*** Funktionen, nur manchmal bringt str***_P keinen RAM Vorteil> weil diese _P Funktion auch RAM braucht, ich wunderte mich das trotz _P> mehr RAM gebraucht wurde, kann ja jeder selbst probieren, mal als _P> kompilieren mal ohne und je nach Textlänge wird das Ergebnis in used Ram> überraschen
Kannst du mal erklären wie diese Funktion RAM belegen sollte? Es handelt
sich einfach nur um Code welcher Bytes aus dem Flash an eine Position im
RAM kopiert. Du scheinst hier irgendwas zu verwechseln bzw. falsch
interpretiert zu haben.
Oder bring mal ein Minimalbeispiel für deine These dann kann man die
besser einordnen.
Cyblord -. schrieb:> Kannst du mal erklären wie diese Funktion RAM belegen sollte? Es handelt> sich einfach nur um Code welcher Bytes aus dem Flash an eine Position im> RAM kopiert. Du scheinst hier irgendwas zu verwechseln bzw. falsch> interpretiert zu haben.
nee kann ich nicht, aber ich bin kein Programmierer und stelle nur fest
das es so ist.
ich vermute der Aufruf der str???_P Routinen braucht RAM, Stack sichern,
Variablen sichern und wieder freigeben, oder RAM für Pointer, was weiss
ich. Es bleibt eine Tatsche das str???_P Routinen dazu gelinkt werden
müssen und das eben nicht ohne Folgen bleibt.
strcpy_P
strcmp_P
strlen_P
sind so Funktionen die ich nutze und ich mit und ohne _P teste also was
für den knappen SRAM im m328 weniger weh tut. Aber selten mal ist RAM
über und flash wird knapp dann natürlich ohne PSTR("hier ist ein langer
Text....")
Joachim B. schrieb:> Cyblord -. schrieb:>> Kannst du mal erklären wie diese Funktion RAM belegen sollte? Es handelt>> sich einfach nur um Code welcher Bytes aus dem Flash an eine Position im>> RAM kopiert. Du scheinst hier irgendwas zu verwechseln bzw. falsch>> interpretiert zu haben.>> nee kann ich nicht, aber ich bin kein Programmierer und stelle nur fest> das es so ist.
Es ist aber Unsinn, also bringe ein Beispiel oder höre auf so einen
Quatsch zu schreiben.
> ich vermute der Aufruf der str???_P Routinen braucht RAM, Stack sichern,> Variablen sichern und wieder freigeben, oder RAM für Pointer, was weiss> ich. Es bleibt eine Tatsche das str???_P Routinen dazu gelinkt werden> müssen und das eben nicht ohne Folgen bleibt.
Alles Unsinn. Den Stackverbrauch beim Funktionsaufruf siehst du in
deinem avr-size gar nicht.
Und es ging hier darum dass Strings selber keinen Ram benötigen. Was du
später mit diesem Strings machst, hat damit nichts zu tun. Wenn du den
String später aus dem Flash irgendwohin kopieren willst, brauchst du
dort natürlich Ram. Hat aber nichts mit der Problematik zu tun.
Joachim B. schrieb:> aber ich bin kein Programmierer und stelle nur fest das es so ist.
Es ist nicht so. Die str*_P-Funktionen verwenden kein RAM - im
statischen Sinne.
Du hast das wahrscheinlich verwechselt mit einem evtl. erhöhten
Flash-Bedarf, der natürlich durch Hinzubinden der str*_P-Funktionen
entstehen kann.
Joachim B. schrieb:> nee kann ich nicht, aber ich bin kein Programmierer und stelle nur fest> das es so ist.
Ich vermute, Du hast einen Fehler gemacht, der dafür gesorgt hat, dass
eben nicht alles im Flash gelandet ist, z.B. Strings im Flash, Pointer
darauf im RAM.
Gerne wird sowas gemacht:
const char test[] = "qwertzui";
In der Hoffnung dass es im Flash landet!
Tut es auch.
Wird aber zusätzlich, in Initphase, ins Ram kopiert.
const char test[] PROGMEM = "qwertzui";
Unterbindet das dann.
Mit der Folge, dass man keinen "gültigen" Zeiger auf die Zeichenkette
erhält. Der Compiler kennt keinen Unterschied zwischen Flash und RAM
Zeigern, für den zeigen alle Zeiger ins RAM.
z.B. die str***_P() Funktionen können mit solchen Flash-Zeigern umgehen.
> [/code]> Warum wird hier der RAM ebenfalls genutzt obwohl das Schlüsselwort const> benutzt wurde? Bin hier gerade etwas überfragt, warum in einer solchen
Die Sache mit Harvard und PROGMEM ist nur sekundär. Das eigentliche
Problem liegt woanders: Das "const" in der Deklaration sagt nur, dass
die Funktion den String als konstant betrachten muss, ihn also nicht
selbst ändern darf. Der Aufrufer ist jedoch frei, nach Belieben einen
Zeiger auf einen konstanten String oder eben auch auf einen
nichtkonstanten String zu übergeben. Die Funktion weiß aber nicht,
welcher Fall eintritt ...
https://stackoverflow.com/questions/39124796/why-is-an-implicit-conversion-from-non-const-to-const-allowed-for-pointers-in-th
A. B. schrieb:> Der Aufrufer ist jedoch frei, nach Belieben einen> Zeiger auf einen konstanten String oder eben auch auf einen> nichtkonstanten String zu übergeben.
Zumindest bei mir nörgelt es etwas rum!
1
#include<Streaming.h> // die Lib findest du selber ;-)
2
Stream&cout=Serial;// cout Emulation für "Arme"
3
4
5
voidboeseFunktion(char*str)
6
{
7
*str='B';
8
}
9
10
voidsetup()
11
{
12
Serial.begin(9600);
13
14
constchar*t1="Hello";
15
constchart2[]="Hello";
16
17
18
boeseFunktion((char*)t1);// eigentlich ist der Cast boese
19
// boeseFunktion(t1); // warning: invalid conversion from 'const char*' to 'char*'
20
21
cout<<t1<<endl;
22
cout<<t2<<endl;
23
cout<<"Hello"<<endl;
24
}
25
26
voidloop()
27
{
28
29
}
Ausgabe:
1
Bello
2
Hello
3
Bello
Die Ausgabe kann bei dir anders aussehen. Der Compiler darf dir auch,
bei der Gelegenheit, das Zimmer tapezieren.
Offensichtlich ist, dass dort eine anonyme Instanz der Zeichenkette im
RAM liegt.
EAF schrieb:> Zumindest bei mir nörgelt es etwas rum!> void boeseFunktion(char *str)
Logisch, das ist ja auch genau umgedreht. Hier wird der Funktion
ausdrücklich erlaubt, in dem String herumzuwurschteln (was sie ja auch
tut). Da darf man natürlich keinen Zeiger auf einen konstanten String
übergeben.
Das mit dem (char *)-cast ist ja auch eine ganz üble Gewalttat ;-)
Von (char *) nach (const char *) ist ok, anders herum aber natürlich
nicht.
Sebastian schrieb:> Cyblord -. schrieb:>> dass der Compiler für ein einziges Bytes gar keinen String anlegt>> "T" ist zwei Bytes gross.>> LG, Sebastian
Auch wieder wahr.
Sebastian schrieb:> Cyblord -. schrieb:>>> dass der Compiler für ein einziges Bytes gar keinen String anlegt>> "T" ist zwei Bytes gross.
Stimmt, aber das terminierende '\0' wird nicht gesendet. Bleibt also das
nackte 'T'.
Joachim B. schrieb:> Cyblord -. schrieb:>> Kannst du mal erklären wie diese Funktion RAM belegen sollte? Es handelt>> sich einfach nur um Code welcher Bytes aus dem Flash an eine Position im>> RAM kopiert. Du scheinst hier irgendwas zu verwechseln bzw. falsch>> interpretiert zu haben.>> nee kann ich nicht, aber ich bin kein Programmierer und stelle nur fest> das es so ist.>
Dann verfatz dich hier uns sei still.