Forum: Mikrocontroller und Digitale Elektronik Probleme mit pgmspace. ATMega1284P hangt sich durch strcpy_P auf


von Felix N. (felix_n888)


Angehängte Dateien:

Lesenswert?

Guten Abend,
Ich habe ein kleines Problem mit meiner Software. Ich hatte letztes 
Jahr(So um Oktober) mal ein Thema hier wo es um mein Aquarium 
Steuergerät ging wo mir der Platz aus ging.


Da ich mich ja dafür entschlossen habe den gesamten Programmcode neu zu 
schrieben anstatt im bestehen Projekt zu überarbeiten, habe ich dieses 
Stück für Stück getan.


Es wurde mir ja mehrmals geraten das ich die String nicht mehr im RAM 
ablegen soll sondern mit den "_P" Funktion und PSTR sowie PROGMEM in den 
Flash auslagere.


Das habe ich auch immer bis jetzt getan(Außer Serielle Nachrichten die 
nur zur Temporären Überprüfung waren wurden ohne _P und PSTR verwendet). 
Nur jetzt habe ich ein Problem und zwar bin ich gerade an dem 
Menüfunktion Netzwerk angelangt, und dort verwende ich ein Switch Case.

In diesem Switch Case lade ich einen String "preIpStr" mit strcpy_P vor. 
Dort steht dann zB. drin "IP" oder "GW". Das Problem liegt am zweiten 
strcpy_P in case Fall 2 wenn ich das drin stehen habe und die 
IP-Adressen im Menü ändern möchte wird mein TFT Display(ili9341) mit 
allen möglich Zeichen ausgefüllt und der Controller hängt sich komplett 
auf.


Nach 4 Sekunden setzt dann der Watchdog Timer den Controller zurück.


Wenn ich aus dem strcpy_P die normale Version mache strcpy funktioniert 
der Programmcode Problemlos.


Kann mir nicht erklären woran das liegt, char Array ist groß genug 
teiweise auch mal auf 100 Bytes erhöht ändert aber nix. Wenn ich das 
strcpy_P aus dem Case Fall 1 entnehme(Also strcpy_P(preIpStr, 
PSTR("IP"));) und im Case Fall 2 es stehen lasse(strcpy_P(preIpStr, 
PSTR("GW"));) dann funktioniert der Code wieder.


Gibt es eine Limitierung bei PSTR/pgmspace? Der RAM ist noch nicht 
Ansatz weiße voll.

Flash aktuell: 41,8kB 32 %
RAM aktuell  : 2,59kB 15 %


Ich habe die Funktion mal angehängt. Sie ist zum Teil kommentiert.


Kann mir da jemand weiter helfen?

Mfg

Beitrag #6168114 wurde vom Autor gelöscht.
von Apollo M. (Firma: @home) (majortom)


Lesenswert?

Felix N. schrieb:
> Es wurde mir ja mehrmals geraten das ich die String nicht mehr im RAM
> ablegen soll sondern mit den "_P" Funktion und PSTR sowie PROGMEM in den
> Flash auslagere.

richtig so, nur die strings standen auch schon vorher im flash und sind 
nur extra zum init ins ram kopiert worden.

Felix N. schrieb:
> Das Problem liegt am zweiten
> strcpy_P

glaube ich nicht, weil da sieht alles ok aus. ich denke an 
bereichsüberschreitung/-schreibung ...

mache debug ausgaben von dem code davor!
bzw. verwende as7 und den simulator um dir codebereiche anzuschauen!


mt

von Pit S. (pitschu)


Lesenswert?

Wo wird denn 'ipByteSelector' initialisiert? Du greifst da mit ...-1 
drauf zu. Wenn der aber 0 ist, gibt's ein Problem

von Felix N. (felix_n888)


Lesenswert?

Apollo M. schrieb:
> richtig so, nur die strings standen auch schon vorher im flash und sind
> nur extra zum init ins ram kopiert worden.

Ach ja, so war das.

Apollo M. schrieb:
> glaube ich nicht, weil da sieht alles ok aus. ich denke an
> bereichsüberschreitung/-schreibung ...

Ah ok.

Apollo M. schrieb:
> mache debug ausgaben von dem code davor!
> bzw. verwende as7 und den simulator um dir codebereiche anzuschauen!

Also mit dem Simulator habe ich das wohl schon mal versucht jedoch komme 
ich da noch nicht wie man den richtig anwendet. Muss da nochmal schauen 
zu mal die Funktion ja nur ausgeführt wird denn ein Knopf gedrückt wird 
und ein bestimmter Wert auf 1 gesetzt wird sonst wird die Funktion ja 
garnicht ausgeführt.

Von was soll ich den genau debug ausgaben machen? Von den Strings?

Pit S. schrieb:
> Wo wird denn 'ipByteSelector' initialisiert?

ipByteSelector ist eine globale uint8_t Variable und wird mit dem Wert 0 
initialisiert.

Pit S. schrieb:
> Du greifst da mit ...-1
> drauf zu.

Huch, wo greife ich den da mit -1 drauf zu? //Edit: Meinst du bei 
eIP[ipByteSelector - 1]?

Mfg

: Bearbeitet durch User
von Felix N. (felix_n888)


Lesenswert?

Apollo M. schrieb:
> glaube ich nicht, weil da sieht alles ok aus. ich denke an
> bereichsüberschreitung/-schreibung ...

Hallo nochmal,

Ich habe nochmal ein bisschen geschaut also Debug Nachrichten auszugeben 
macht kein Sinn da solange das zweite strcpy_P drin steht da keine Debug 
Nachrichten mehr an den UART gesendet werden sobald die Funktion 
aufgerufen wird auch wenn die Sendung der Nachrichten vor dem strcpy_P 
erfolgt.

Komisch ist ja das der Programmcode Problemlos funktioniert wenn ich den 
String in den RAM lade und nicht über PSTR ablege.

Auch Ausblenden einzelner Codeteile vor und nach dem strcpy_P nach nix 
gebracht der Code funktioniert nur wenn das strcpy_P durch strcpy 
ersetzt wird oder das strcpy_P komplett raus genommen wird.

Nochmal zu dem ipByteSelector das ist ja wie schon erwähnt eine globale 
Variable die mit 0 initialisiert wird. Bevor jedoch die changeIP() 
Funktion aufgefunden wird(Diese Funktion ist ja nur dafür da die Werte 
zu ändern) wird eine andere Funktion aufgerufen welche den 
ipByteSelector zuweist. Beim ersten Knopfdruck wird der Selector auf 1 
gesetzt und wählt damit das erste Byte der IP-Adresse aus bei nächsten 
drücken wird der um 1 erhöht und wählt dann das zweite Byte aus geht alt 
bis 4 dann wird er zurückgesetzt.

Nur kann ich mir das mit dem strcpy_P nicht erklären. Es macht für mich 
irgendwie kein sinn.

mfg

: Bearbeitet durch User
von Felix N. (felix_n888)


Lesenswert?

Guten Abend nochmal an alle,

Es hat zwar in der zwischen Zeit keiner geantwortet jedoch habe ich 
selber noch fleißig weiter gesucht und konnte das Problem teilweise 
lösen kann es mir aber immer noch nicht erklären warum das so ist.

Also was ich mittlerweile feststellen konnte das das Problem wohl nicht 
an dem zweiten strcpy_P liegt sondern wahrscheinlich an dem:
1
sprintf_P(strIP, PSTR("%03d"), eIP[ipByteSelector - 1]);                      //Format String to drawing

Wenn ich die sprintf_P Zeile auskommentiere funktioniert der Code wieder 
Problemlos aber gleichzeitig wenn ich die sprintf_P Zeile drin lasse und 
oben eine der strcpy_P auskommentiere funktioniert der Code auch. Wie 
kann das???

Also eIP und ipByteSelector sind gültig und auch initialisiert. Daher 
keine Probleme ipByteSelector hat zum Zeit Punkt den Wert 1 und in 
eIP[0] steht dann der entsprechen Wert.


Ich habe jedoch noch das 03 in dem %d drin damit wenn man eine Zahl 
unter 100 eingibt das dort nicht 99 steht sondern 099 weil sich sonst 
die ganze Display Zeile verschiebt und das alles dann nicht mehr richtig 
funktioniert.

Jedoch wenn ich das %03d zu einem einfach %d ersetzt funktioniert der 
Code Problemlos.


Ich kann mir das nicht erklären wieso das so ist. Habt ihr vielleicht 
eine Idee? Zumal ich die Zeile mit dem sprintf_P schon öfters in 
Kombination mit %03d bzw. %02d verwendet habe und es gab in der Hinsicht 
noch nie Probleme.

Komisch das ganze ...

Mfg

von Totomitharry (Gast)


Lesenswert?

Minimiere doch mal den kompletten Code mit bestehendem Problem als 
snippet.

von Peter D. (peda)


Lesenswert?

Felix N. schrieb:
> Jedoch wenn ich das %03d zu einem einfach %d ersetzt funktioniert der
> Code Problemlos.

Dann ist der Puffer strIP zu klein oder ungültig.

Felix N. schrieb:
> sprintf_P(strIP, PSTR("%03d"), eIP[ipByteSelector - 1]);

"Zeiger/Index - 1" sollte man generell vermeiden. Bei jedem Profi läuten 
da sofort die Alarmglocken.

von Johannes S. (Gast)


Lesenswert?

gibt es auch ein snprintf_P? Die n Versionen würde ich sowieso 
bevorzugen.

> eIP[ipByteSelector - 1]
Da könnte man auch ein ASSERT() Makro für einen Debugbuild verwenden.
Das %03 nicht funktioniert und %3 doch hört sich ja schon nach einem 
Grössenproblem an.

Oder du hast dir vorher einen Stackfehler eingefangen, das macht sich 
auch gerne erst später bemerkbar.

von Felix N. (felix_n888)


Lesenswert?

Hallo an alle,

Totomitharry schrieb:
> Minimiere doch mal den kompletten Code mit bestehendem Problem als
> snippet.

Ja das Problem ist ja das dieses Problem sich durch andere 
Programmzeilen beeinflussen lässt. Daher wird es schwierig.

Denn was ich nun herausgefunden habe ist das dort zwischen den strcpy_P 
und dem sprintf_P noch eine sprintf_P Zeile drin steht:
1
sprintf_P(strIP, PSTR("%03d"), eIP[ipByteSelector - 2]);

Auch da ist wieder das Problem das wenn ich das %03d zu einem %3d oder 
%d der Code wieder funktioniert.

Peter D. schrieb:
> Dann ist der Puffer strIP zu klein oder ungültig.

Hatte ich auch schon dran gedacht jedoch habe ich bereits oben in der 
Funktion direkt nach den anlegen der Lokalen Variablen versucht die 
Puffers mit memset() mit 0 zu initialisieren. Jedoch ohne Erfolg.

Auch habe ich die Puffergröße von 10 test weiße mal auf 100 Bytes 
vergrößert aber das Problem tritt dann immer noch auf.

Peter D. schrieb:
> "Zeiger/Index - 1" sollte man generell vermeiden.

Ich kann mir vielleicht vorstellen warum wenn der Index 0 beträgt und 
ich minus 1 rechne und die Variable vom Typ unsigned ist kann sie ja 
nicht Negativ werden und es kommt zum Fehler oder?

Nur wie soll ich das ganze den anderes machen? Der Index ist nun mal 
beim Aufruf schon 1 und ich muss es im Index des Arrays 0 speichern 
alternativ könnte ich den Index 0 vom Array unbelegt lassen dann kann 
ich ohne das minus 1 auskommen. Ist das die einzige Möglichkeit?

Johannes S. schrieb:
> gibt es auch ein snprintf_P? Die n Versionen würde ich sowieso
> bevorzugen.

Ich habe mal kurz geschaut also die Funktion gibt es. Wenn ich die 
snprintf Funktion richtig verstehe übergibt man als zweites Argument die 
Größe des Puffers damit die Funktion nicht mehr in den Puffer schreiben 
kann als der groß ist und somit "Overflows" verhindert werden? Oder 
warum ist Sie besser?

Johannes S. schrieb:
> Das %03 nicht funktioniert und %3 doch hört sich ja schon nach einem
> Grössenproblem an.

Grössenproblem? Ich meine ich brauche ja die führenden Nullen davor 
damit der Text korrekt auf dem Display anzeigt wird. Arbeite jedoch auch 
nicht zum ersten mal mit %03d bis jetzt hat das immer Problemlos 
funktioniert.

Scheint irgendwie ein Problem mit den führenden Nullen zu seinen den %3d 
lässt ja 2 Platz nach linkes ohne es mit nullen aufzufüllen.

Was ich aber einfach nicht verstehe warum funktioniert der Programmcode 
wenn ich ich die normale sprintf Funktion verwende also den String in 
den RAM lade?

Johannes S. schrieb:
> Oder du hast dir vorher einen Stackfehler eingefangen, das macht sich
> auch gerne erst später bemerkbar.

Ok oder auch nicht. Wie kann ich das jetzt ausfinden?

von Johannes S. (Gast)


Lesenswert?

Felix N. schrieb:
> Ich kann mir vielleicht vorstellen warum wenn der Index 0 beträgt und
> ich minus 1 rechne und die Variable vom Typ unsigned ist kann sie ja
> nicht Negativ werden und es kommt zum Fehler oder?

da macht dir der Compiler eine implizite Konvertierung und evtl. eine 
Warnung. Aber das kann man doch einfach blocken wenn am Anfang der 
Funktion eine Prüfung auf <= 0 mit Ausgabe von Fehlermeldung und return 
gemacht wird.

von Felix N. (felix_n888)


Lesenswert?

Johannes S. schrieb:
> da macht dir der Compiler eine implizite Konvertierung und evtl. eine
> Warnung. Aber das kann man doch einfach blocken wenn am Anfang der
> Funktion eine Prüfung auf <= 0 mit Ausgabe von Fehlermeldung und return
> gemacht wird.

Hallo,

Achso du meinst das der Compiler dann aus dem uint8_t einfach ein int8_t 
macht? Meinst du dann sowas?:
1
if(ipByteSelector <= 0) {
2
   return;
3
}
4
5
//Sonst sprintf etc...

Werde ich mir mal im Hinterkopf behalten. Jedoch wenn ich aus der 
sprintf Funktion die Variable eIP[ipByte... -2] raus nehme und dort fest 
einfach zB. 50 reinschreibe. Tritt der Fehler ja immer noch auf.

Mfg

von Oliver S. (oliverso)


Lesenswert?

Felix N. schrieb:
> Achso du meinst das der Compiler dann aus dem uint8_t einfach ein int8_t
> macht?

Nein, der macht daraus ein unsigned int. Was an dem Problem nichts 
ändert...

Oliver

von Peter D. (peda)


Lesenswert?

Felix N. schrieb:
> Hatte ich auch schon dran gedacht jedoch habe ich bereits oben in der
> Funktion direkt nach den anlegen der Lokalen Variablen versucht die
> Puffers mit memset() mit 0 zu initialisieren. Jedoch ohne Erfolg.

memset kann Deinen Puffer nicht vergrößern, ist hier also sinnlos.
Welche Größe hast Du denn memset übergeben?

Felix N. schrieb:
> Der Index ist nun mal
> beim Aufruf schon 1

Warum denn, hast Du irgendwo ein Increment an der falschen Stelle?
Wenn es für die Nutzeranzeige ist, dann rechne intern ab 0 und addiere 1 
nur für die Anzeige.

von Felix N. (felix_n888)


Lesenswert?

Peter D. schrieb:
> memset kann Deinen Puffer nicht vergrößern, ist hier also sinnlos.

Hi, ja ich weiß das memset die Größe nicht verändern kann aber damit 
kann ich das Array initialisieren. Damit es nicht NULL ist. Im Moment 
hat der Puffer strIP eine Größe von 100 Bytes.

Peter D. schrieb:
> Welche Größe hast Du denn memset übergeben?

So habe ich es gemacht:
1
char strIP[10];
2
3
memset(strIP, 0x00, sizeof(strIP));

Peter D. schrieb:
> Warum denn, hast Du irgendwo ein Increment an der falschen Stelle?
> Wenn es für die Nutzeranzeige ist, dann rechne intern ab 0 und addiere 1
> nur für die Anzeige.

Ja sorry, ich habe mir den Teil mit dem ipByteSelector angesehen ich 
kann auch mit 0 anfangen warum ich da jetzt 1 genommen habe weiß ich 
nicht mehr jedoch ist das nur ein Index im Code er wird also nie auf der 
Anzeige erscheinen. Er ist nur dafür die Bytes in der IP-Adresse 
auszuwählen da eine IPv4 Adresse 4 Bytes hat habe ich wahrscheinlich 1 = 
1 Bytes, 2 = 2 Bytes etc... genommen. Das werde ich dann auf 0 abändern 
also 0 = 1 Bytes etc...

Jedoch muss ich an einer Stelle immer noch -1 rechnen. Denn ich habe ja 
immer noch die Abfrage drin wo geprüft wird ob der ipByteSelector größer 
als 1 ist und wenn ja wird das vorherige Byte auf dem Display weiß 
dargestellt und das neue Byte welches jetzt ausgewählt ist zum 
bearbeiten in Rot. Da muss ich ja dann -1 rechnen um den vorherigen Wert 
zu bekommen. Oder wie soll ich das da machen?
1
if(ipByteSelector > 1) {
2
    ili9341_fillrect((x - 49), (y - 1), clrWidth, clrHeight, BLACK);
3
    snprintf_P(strIP, sizeof(strIP), PSTR("%03d"), eIP[ipByteSelector - 1]);
4
    ili9341_combo((x - 49), y, WHITE, BLACK, 2, 3, 0, 0, strIP);
5
}

Es wird dort ja erst geprüft ob der Selector größer als 1 ist(Später 
dann größer als 0 wenn ich es geändert habe). Wenn es so ist wird mit 
fillrect der Bereich wo die Zahl steht(zB. 192) mit einem schwarzen 
Kästchen überlagern damit die Zahlen sich nicht überlappen. Dann wird 
mit snprintf_P der vorherige Wert entsprechend Formatiert mit führenden 
Nullen. Und ili9341_combo ist eine Funktion die alles vereinigt also 
Koordinaten setzten, Text/Hintergrundfarbe wählen, Schriftgröße etc... 
und dann wird der vorherige Wert in Weiß wieder angezeigt.

Der Teil muss doch eigentlich Safe sein oder nicht? Weil ich prüfe doch 
vorher ob ich den Selector - 1 nehmen darf durch die if Abfrage.


Aber es scheint irgend ein Problem mit den führenden Nullen zu seinen, 
denn ich habe noch was raus gefunden den in einer anderen Funktion die 
das Menü "malt" habe ich folgende Programmzeile drin:
1
  sprintf_P(strBuffer, PSTR("IP : %d.%d.%d.%d"), MyIP[0], MyIP[1], MyIP[2], MyIP[3]);
2
  ili9341_combo(4, 77, WHITE, BLACK, 2, 3, 0, 0, strBuffer);

Sie stellt die Server IP Adresse im Menü da. strBuffer ist ein Puffer 
mit einer Größe von 400 Bytes und in der main.h angelegt ist der String 
Puffer für alles(Debug, Menüs malen etc...)

Wenn ich dort das erste %d durch ein %03d ersetzte passiert noch nix 
ersetze ich das zweite %d auch durch ein %03d so das ich dort 
"%03d.%03d.%d.%d" stehen habe. Und das Menü aufrufe hängt sich der 
Prozessor wieder auf sobald der das Menü darstellen will. Mache ich aber 
wieder nur %3d bei allen 4 funktioniert es wieder Problemlos nur halt 
ohne führenden Nullen dafür dann mit entsprechend vielen Leerzeichen 
dazwischen.


Mfg

von Philipp K. (philipp_k59)


Lesenswert?

Also bei mir funktioniert allein das nicht:

Vielleicht hab ich ja etwas übersehen
1
char strIP[10];
2
char strBuffer[100];
3
int MyIP[4] = {111, 111, 111, 111};
4
void setup() {
5
  // put your setup code here, to run once:
6
  memset(strIP, 0x00, sizeof(strIP));
7
  Serial.begin(115200);
8
}
9
10
void loop() {
11
  // put your main code here, to run repeatedly:
12
  sprintf_P(strBuffer, PSTR("IP : %d03.%d03.%d.%d"), MyIP[0], MyIP[1], MyIP[2], MyIP[3]);
13
  Serial.println(strBuffer);
14
}

von Felix N. (felix_n888)


Lesenswert?

Hallo Philipp,

Philipp K. schrieb:
> %d03.%d03

Du hast %d03 geschrieben. Versuchs mal mit %03d also 03 vor dem d. Bei 
mir funktioniert das ganze schon. Aber halt nur mit der sprintf Funktion 
ohne das _P am Ende.

Kann es ein das du die Arduino IDE nutzt? Ich weiß jetzt nicht sicher ob 
es die "_P" Funktion in der Arduino gibt.

Mfg

von Philipp K. (philipp_k59)


Lesenswert?

Ups, ja mein Fail.

Reproduziere das doch mal selbst in einem gekürzten Code.

Ersetzte  mal das sprintf durch eine Zuweisung des eigentlichen 
Ergebnisses.. um Pufferüberläufe zu testen.

Edit: wieviel stellen sind in den String Arrays reserviert? Kann man mit 
den schnippeln nur schätzen. Muss einer mehr für den Abschluss sein.

Eine IP bräuchte 17 arrayelemente

: Bearbeitet durch User
von Felix N. (felix_n888)


Angehängte Dateien:

Lesenswert?

Philipp K. schrieb:
> Ups, ja mein Fail.

Hallo,

Ich scheine wohl erstmal den Fehler gefunden zu haben. Ich habe gerade 
einfach mal die changeIP() Funktion komplett ausgeblendet so das diese 
nicht mehr aufgerufen wird.

Es gibt aber noch eine andere Funktion die nennt sich editIPs() diese 
wird als erstes aufgerufen wenn man die IP-Adressen bearbeiten möchte 
und markiert dann entsprechend den Namen der IP-Adresse in Rot so das 
man weiß welche man ausgewählt hat.


Nachdem nur noch die editIPs() Funktion drin war und der Fehler immer 
noch aufgetreten ist, also das sich der Controller aufhängt habe ich 
diese Funktion auch mal ausgeblendet so das sie nicht mehr aufgerufen 
wird. Danach hängt sich der Controller nicht mehr auf.


Also habe ich mir den Code nochmal genauer angeschaut. Dort habe ich 
auch zwei lokale char Arrays einmal ipStr und preIpStr beide mit einer 
Größe von 10 Bytes. Die Variable ipStr ist für die ausgewählte 
IP-Adresse und preIpStr für die vorherige Adresse.


Da aber nicht immer eine vorherige Adresse vorhanden ist musste ich das 
zweite Array dennoch belegen und zwar habe ich das so gemacht:
1
strcpy_P(preIpStr, NULL);

Habe jetzt test weiße das ganze durch folgendes ersetzt:
1
strcpy_P(preIpStr, PSTR(""));

Habe nämlich die Vermutung das das "NULL" daran schuld gewesen sein 
könnte. Denn jetzt funktioniert der gesamte Code Problemlos. Warum aber 
der Code teilweise funktioniert wenn man in einer anderen Funktion was 
geändert hat. Keine Ahnung.

Werde es jetzt mal testen und weiter programmieren ob dieser Fehler 
wirklich weg bleibt.

Ich habe mal meine ethernetMenu.c Datei angehängt.

Mfg

von Carl D. (jcw2)


Lesenswert?

Was wird

strcpy_P(preIpStr, NULL);

Auf einem AVR wohl machen?
Es kopiert den Anfang des Flash bis zur ersten gefundenen '\0'. Und das 
kann ein paar Bytes dauern, wenn die zig Int-Vectoren mit "JMP Badint" 
vorgelegt sind.
Besser eine (falls verfügbar) "n"-Variante der Str-Routine benutzen.

: Bearbeitet durch User
von Felix N. (felix_n888)


Lesenswert?

Carl D. schrieb:
> Es kopiert den Anfang des Flash bis zur ersten gefundenen '\0'.

Hallo Carl,

Das heißt wenn ich strcpy_P mit NULL als zweites Argument übergebe 
kopiert er alles in den Puffer rein bis er ein \0 gefunden hat? Bedeutet 
also zb. Wenn es von Flash Adresse 0x00 bis zum zB. 0xFF alles kopiert 
weil 0xFF ein \0 beinhaltet?

Und da der Puffer nicht groß genug ist stürzt er dann ab? Richtig so?

Carl D. schrieb:
> Besser eine (falls verfügbar) "n"-Variante der Str-Routine benutzen.

Ja es gibt eine strncpy_P Variante die will Quelle, Ziel und Größe als 
Argumente haben. Quelle und Ziele ist ja klar und als Größe kann ich 
dann einfach mit sizeof und dann die Größe des Puffers übergeben?

Also kann ich besser die "n" Funktion verwenden weil wenn er mehr Daten 
kopiert/schiebt etc... die Funktion einfach aufhört wenn das Limit was 
als dritte Argument übergeben wird überschritten wird? Oder steht dann 
nur das bis zum Limit in Puffer?

Mfg

von Carl D. (jcw2)


Lesenswert?

Felix N. schrieb:
> Carl D. schrieb:
>> Es kopiert den Anfang des Flash bis zur ersten gefundenen '\0'.
>
> Hallo Carl,
>
> Das heißt wenn ich strcpy_P mit NULL als zweites Argument übergebe
> kopiert er alles in den Puffer rein bis er ein \0 gefunden hat? Bedeutet
> also zb. Wenn es von Flash Adresse 0x00 bis zum zB. 0xFF alles kopiert
> weil 0xFF ein \0 beinhaltet?
>
> Und da der Puffer nicht groß genug ist stürzt er dann ab? Richtig so?
Genau!

NULL aka 0 ist eine gültige Flash-Adresse. NULL als "nix" anzusehen ist 
eine Vereinbarung (die auf mancher HW/manchen OS durchgesetzt wird, aber 
auf AVR eben nicht). Denn Flash(0) beinhaltet (das erste Byte) eines 
Sprungs zu "Start"-Routine. Was Konventions ist, daß GCC/AVRLibc die 
Int-Vektoren zumindest mit einen Sprung zu BadInt() füllen. Das können 
0-Bytes vorkommen, oder meist eben auch nicht. Danach kommen dann (falls 
C++) Adressen der Initialisierungsroutinen für globale Objekte. Dann 
eventuell benutzte PROGMEN Strings. Letztere würden die Kopierwut von 
strcpy_P() bremsen, aber da ist es sicher schon zu spät.


> Carl D. schrieb:
>> Besser eine (falls verfügbar) "n"-Variante der Str-Routine benutzen.
>
> Ja es gibt eine strncpy_P Variante die will Quelle, Ziel und Größe als
> Argumente haben. Quelle und Ziele ist ja klar und als Größe kann ich
> dann einfach mit sizeof und dann die Größe des Puffers übergeben?
>
> Also kann ich besser die "n" Funktion verwenden weil wenn er mehr Daten
> kopiert/schiebt etc... die Funktion einfach aufhört wenn das Limit was
> als dritte Argument übergeben wird überschritten wird? Oder steht dann
> nur das bis zum Limit in Puffer?
>
> Mfg

Die Funktion kennt vom Ziel nur die Adresse, die Länge muß zusätzlich 
mitgegeben werden, andernfalls kommt die Länge aus der Quelle, und zwar 
nach der C-String-Konvention "endet mit '\0'".

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Felix N. schrieb:
> strcpy_P(preIpStr, NULL);

Das ist natürlich ganz großer Mist.
NULL nimmt man, um einen Pointer als ungültig zu kennzeichnen, d.h. mit 
einem solchen Pointer dürfen auf keinen Fall irgendwelche Aktionen 
erfolgen.
Erlaubt ist nur, einen solchen Pointer auf NULL zu testen oder ihm eine 
gültige Adresse zuzuweisen.
Z.B. malloc liefert NULL, wenn kein Speicher belegt werden konnte.

von Oliver S. (oliverso)


Lesenswert?

Carl D. schrieb:
>
> NULL aka 0 ist eine gültige Flash-Adresse. NULL als "nix" anzusehen ist
> eine Vereinbarung (die auf mancher HW/manchen OS durchgesetzt wird, aber
> auf AVR eben nicht).

Ist aber völlig egal, die Verwendung von NULL als *src ist schlicht 
falsch, und führt zum Fehler.

Oliver

von Peter D. (peda)


Lesenswert?

Carl D. schrieb:
> NULL aka 0 ist eine gültige Flash-Adresse.

Nur stehen dort keine Strings, sondern Befehle.
D.h. man könnte höchstens dahin springen, um einen SW-Reset zu bewirken.

von Felix N. (felix_n888)


Lesenswert?

Carl D. schrieb:
> Genau!

Oliver S. schrieb:
> ist schlicht
> falsch, und führt zum Fehler.

Hallo nochmal,

Ach ja selbst eingebaute Fehler sind ja eh die besten :)

Peter D. schrieb:
> Nur stehen dort keine Strings, sondern Befehle.

Eine Frage bleibt mir da noch. Wenn strcpy im Flash an der Adresse 0 
angefangen hat und bis zu einem \0 gesucht hat aber am Anfang nur 
Befehle stehen wieso kann es dann sein das wenn ich teilweise String 
Funktion ohne _P verwende ohne andere String Funktion ausblende das der 
Programmcode trotzdem funktioniert?

Peter D. schrieb:
> NULL nimmt man, um einen Pointer als ungültig zu kennzeichnen

Ach so ok. Ich dachte das wenn ich als weites Argument NULL übergebe das 
er in den String dann einfach auf 0 setzt. Da lag ich wohl daneben. 
Immerhin etwas neues dazu gelernt :)

Also ich habe meine Funktion nun fast vervollständigt es fehlt jetzt nur 
noch der Teil mit dem Server Port dann ist sie fertig. Bis jetzt trat 
der Fehler nicht mehr auf. Ich denke mal das es dann wirklich nur an dem 
NULL lag.

Möchte mich auf jeden Fall bei allen die mir hierbei geholfen haben 
Bedanken!

Vielen Dank an euch!

Mfg

von Oliver S. (oliverso)


Lesenswert?

Felix N. schrieb:
> wieso kann es dann sein das wenn ich teilweise String
> Funktion ohne _P verwende ohne andere String Funktion ausblende das der
> Programmcode trotzdem funktioniert?

Weil an RAM-Adresse 0 das Register r0 gemappt ist, und das wird vom gcc 
dauerhaft auf den Wert 0 gesetzt.

Oliver

von Carl D. (jcw2)


Lesenswert?

Für alle die das vielleicht falsch verstanden haben könnten:
Ich hab beschrieben, was konkret auf der HW passiert und nicht zum 
Ausdruck bringen wollen, daß was der TO "codiert" hat richtig wäre. 
Offensichtlich ist es falsch, denn es führt zum Chaos. Den Weg dorthin 
wollte ich ihm erklären.

von Leo C. (rapid)


Lesenswert?

Felix N. schrieb:
> Peter D. schrieb:
>> NULL nimmt man, um einen Pointer als ungültig zu kennzeichnen
>
> Ach so ok. Ich dachte das wenn ich als weites Argument NULL übergebe das
> er in den String dann einfach auf 0 setzt. Da lag ich wohl daneben.
> Immerhin etwas neues dazu gelernt :)

Felix N. schrieb:
> Habe jetzt test weiße das ganze durch folgendes ersetzt:
> strcpy_P(preIpStr, PSTR(""));

Was Du eigentlich willst ist:
1
*preIpStr = '\0';
oder
1
preIpStr[0] = '\0';

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.