Forum: PC-Programmierung Nach Initialisierung falsche Werte im Struct


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Artur (arwar)


Angehängte Dateien:

Lesenswert?

Halo Kollegen.
Komme mit Initialisierung einer Struktur nicht weiter.
Mikrokontroller - STM32-F103-Olimex,  IDE – Eclipse,  Compiler - GCC, 
G++

Der Compiler meckert nicht  aber die Werte der initialisierten Struktur 
sind  falsch.

Die Struktur beschreibt einen Zeichensatz (Font) für die Ausgabe am LCD 
Display.
1
//Display.h
2
3
#parma   //--- wird vom Compiler ignoriert ???
4
5
typedef struct {
6
const short *table;  // Tabelle mit den Font Daten
7
  short width;    // Breite des Zeichens (in Pixel)
8
  short height;    // Hoehe  des Zeichens (in Pixel)
9
}Font_t;

Anderen Daten und Code sind im „Display.c“ gesammelt um den Fehler zu 
lokalisieren.

Die Font Tabelle  (*table).
1
const short Arial_7x10_Table [] = {
2
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Ascii = [ ]
3
0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x00,0x00, // Ascii = [!]
4
 . .  insgesamt 95 Zeilen, je 10 Hex Werte
5
};

Initialisierung
1
Font_t Arial_7x10 = {      //Variable Arial_7x10 erzeugen, Typ Font_t
2
  .table = Arial_7x10_Table,  // Adresse der ZeichenTabelle zuweisen
3
  .width = 7,        // Schriftbreite setzen
4
  .height = 10        // Schrifthöhe   . . .
5
};

Beim Debuggen - kein Wert stimmt: Variable   .width sollte = 7 sein, 
.height = 10.
---Bild „StructDaten.png“

Tabelle hat eine falsche Adresse.
 ---Bild „Tabelle.png“.

Man könnte es mit der Tabellenadresse vergeigen, aber 2 anderen Werte 
sind doch DIREKT zugewiesen.

Was mache ich falsch?????

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Artur schrieb:
> #parma   //--- wird vom Compiler ignoriert ???

Dem fehlt der Schinken.

Regel#1 hier im Forum und auch anderswo: immer den Original-Quellcode 
zeigen.
Regel#2 hier im Forum und auch anderswo: immer den ganzen Quellcode 
zeigen.

Stackoverflow, Array out of bounds, oder wie auch immer du die Daten 
überschreibst.

Oliver

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Entweder dein Startupcode oder Linkerscript ist defekt, oder die 
Variable Arial_7x10 wird von einem "wilden Pointer" überschrieben 
(Buffer Overflow o.ä.).

Wenn das Programm ganz am Anfang ist (Anfang der main()), sind die Daten 
dann richtig? -> Watchpoint drauf setzen und laufen lassen.

Sind die Daten da schon falsch? Breakpoint im Startupcode NACH das " bcc 
CopyDataInit" setzen und schauen ob es dann stimmt - wenn ja, Watchpoint 
setzen und laufen lassen. Wenn nein, ist was am Startupcode/Linkerscript 
kaputt.

von Alexander (alecxs)


Lesenswert?

Welches Flag für Compiler Optimierung hast Du gesetzt? versuche es mal 
mit -Og

Beitrag #7705425 wurde vom Autor gelöscht.
von J. S. (jojos)


Lesenswert?

Die Fehlermeldungen vom Debugger sehen nicht gut aus, da werden doch nur 
Fahrkarten angezeigt?

von Artur (arwar)


Lesenswert?

Niklas G. schrieb:
>
> Wenn das Programm ganz am Anfang ist (Anfang der main()), sind die Daten
> dann richtig? -> Watchpoint drauf setzen und laufen lassen.
>

> von Oliver S. (oliverso)
>Stackoverflow, Array out of bounds, oder wie auch immer du die Daten
>überschreibst.
>

Danke für den Tipp.
Hab einen kleine Struct erzeugt und diesen intialisiert an der gleichen 
Stelle mit dem alten Struct - auch der neuer Strukt wurde falsch 
initialisiert.

Am Anfang des Programms (Anfang der main()) hat alles sauber geklappt.
Muss mal sehen wie ich den Stack checken kann.

von Εrnst B. (ernst)


Lesenswert?

Artur schrieb:
> Am Anfang des Programms (Anfang der main()) hat alles sauber geklappt.

Die Structs werden nicht durch "Magie" befüllt, das macht der µC schon 
schön selber in seinem Startup-Code. Wenn du deinen Breakpoint zu früh 
hast, kannst du dem µC zuschauen, wie er der Reihe nach seine globalen 
Variablen und Structs initialisiert. Am Anfang von "main" ist er damit 
fertig...

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Artur schrieb:
> Muss mal sehen wie ich den Stack checken kann.

Setze einfach einen Watchpoint auf das struct und lasse das Programm 
laufen. Das Programm wird dann genau an der Stelle unterbrechen wo der 
fehlerhafte Zugriff ist. Geht blitzschnell.

von Jens M. (schuchkleisser)


Lesenswert?

Warum ist der Font für das Display "Short" (das sind Bytes), und warum 
sollte die Struct erst initialisiert werden müssen? Die ist doch wohl 
hoffentlich im Flash? Oder ist der Prozessor behindert und kann 
Displaydaten nur aus dem RAM lesen?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Jens M. schrieb:
> Die ist doch wohl hoffentlich im Flash

Nein, weil kein "const" dran steht kommt es in den RAM und muss erst 
kopiert werden.

von Harald K. (kirnbichler)


Lesenswert?

Jens M. schrieb:
> Warum ist der Font für das Display "Short" (das sind Bytes)

Wenn der Font auch breiter werden kann als 8 Pixel, könnte das einen 
Sinn haben - aber warum dann ein Datentyp mit Vorzeichen?

von Jens M. (schuchkleisser)


Lesenswert?

Niklas G. schrieb:
> Nein, weil kein "const" dran steht kommt es in den RAM und muss erst
> kopiert werden.

Soweit mir bekannt wird auch const bei manchen Prozessoren im RAM (oder 
gar in Registern) gelagert, weil schneller/kürzer zugreifbar.
Zumindest bei AVRs muss man auch noch PROGMEM angeben, um es sicher ins 
Flash zu packen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Jens M. schrieb:
> Soweit mir bekannt wird auch const bei manchen Prozessoren im RAM (oder
> gar in Registern) gelagert

Ja, hängt vom Linkerscript ab. Aber beim STM32 wird normalerweise alles 
was "const" ist in den Flash gelegt.

von Artur (arwar)


Lesenswert?

Hallo Kollegen.
Hatte in der Woche leider nicht viel Zeit aber immer hin gibt es ein 
Ergebniss.  . .

So lief es weiter

- die Tabelle(nur 2 Zeilen), die Definition der Struktur und die 
Initialisierung -->  ganz am Anfang der  main() eingetragen  ->  hat 
nicht geholfen

 -  die Tabelle fest definiert -> statt []  ein   [2][10] eingetragen
1
const unsigned short Arial_7x10_Table[2][10] = {
2
  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 
3
  {0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x00,0x00},
4
};
 Erst jetzt wurde der Struct ordentlich initialisiert - alle Werte in 
den Variable richtig eingetragen.

 - Definition der Struktur aus main() in "Display.h" versetzt  - 
funktionierte auch.

 - komplette Tabelle am Anfang der  Main() eingetragen (95 Zeilen).
Compiler hat sich "verschluckt" und ist mit der Meldung "undefined 
reference to memcpy'"  ausgestiegen.
Der Eintrag #include "string.h" hat nicht geholfen.
Erst eine weitere Ergänzung der Tabellendefinition mit "static" hat mich 
weitergebracht
1
"static const unsigned short Arial_7x10_Table[95][10] . . . "

- Die gesamte Tabelle ins "Display.h" verschoben - geht auch :-)

Also mit einer Schrift (Font) könnte man es so belassen.
Wenn man aber 2 - 3 Fonts hat, wird die Header "überladen" wirken.
Geschickter wäre es pro Font eine Separate Datei zu haben - aber genau 
das funktioniert noch nicht hinbekommen.


Bin dran :-)))

von Oliver S. (oliverso)


Lesenswert?

Artur schrieb:
>  - komplette Tabelle am Anfang der  Main() eingetragen (95 Zeilen).
> Compiler hat sich "verschluckt" und ist mit der Meldung "undefined
> reference to memcpy'"  ausgestiegen.

Spätestens an der Stelle sollte klar sein, daß deine toolchain kaputt 
ist.

Oliver

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> Spätestens an der Stelle sollte klar sein, daß deine toolchain kaputt
> ist.

Es ist extrem unwahrscheinlich, dass der GCC bei so etwas simplen 
versagt.

Artur schrieb:
> So lief es weiter

Du doktorst an den Symptomen rum. Du hast irgendwo einen Buffer Overflow 
o.ä. Den findest du so nicht. Der wird dich später anderweitig in den 
allerwertesten beißen, du hast so eine Zeitbombe im Code.

Auf die Gefahr mich zu wiederholen: Benutze einen Data Watchpoint. Damit 
hast du das eigentliche Problem in 2 Minuten gefunden. Ohne 
Rätselraten und Rumprobieren.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Niklas G. schrieb:
> Es ist extrem unwahrscheinlich, dass der GCC bei so etwas simplen
> versagt.

Es ist extremst unwahrscheinlich, das eine intakte toolchain ein
„undefined reference to memcpy“ auswirft.

Oliver

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> Es ist extremst unwahrscheinlich, das eine intakte toolchain ein
> „undefined
> reference to memcpy“ auswirft.

Das ist sogar sehr wahrscheinlich. Intakte toolchains tun das ständig. 
Bei fehlerhaftem Code eben. Der hier sehr wahrscheinlich vorliegt. Aber 
diesen kennen wir ja nicht.

Artur schrieb:
> komplette Tabelle am Anfang der  Main() eingetragen (95 Zeilen).

Wenn man die Tabelle als lokale Variable in die main() schreibt MUSS 
eine intakte Toolchain diesen Fehler liefern, wenn man versucht von 
anderen Stellen aus "direkt" darauf zuzugreifen.

: Bearbeitet durch User
von Artur (arwar)


Lesenswert?

Oliver S. schrieb:
>
> Spätestens an der Stelle sollte klar sein, daß deine toolchain kaputt
> ist.
>

Könnte gut sein.  Leider hab ich von Einstellungen in "Eclipse" nicht 
viel Ahnung. Die IDE wurde mir vor Jahren vom Arbeiskollegen in 
Frankfurt eingerichtet. Ich bin "weit weg" aus Frankfurt nach Paderborn 
umgezogen und den Kontakt verloren. So programmiere ich immer noch 
Hobbymäßig mit der alten Einrichtung / Umgebung.
Leider, sind Programmierer "meiner Klasse"(Über 70 und immer noch in 
"C") in meiner Umgebung nicht zu finden. Würde mich tierisch freuen eine 
"verwandte Sehle" in der Nähe zu haben.

Könnte aber auch gut sein dass die IDE sehr "mager" eingerichtet ist so 
dass die Programme auf mehreren MK laufen werden.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Wenn du dein gesamtes ursprüngliches Programm (das bei dem die 
Initialisierung problematisch ist) zeigen würdest, könnte man drauf 
schauen.

von Wastl (hartundweichware)


Lesenswert?

Niklas G. schrieb:
> Wenn du dein gesamtes ursprüngliches Programm (das bei dem die
> Initialisierung problematisch ist) zeigen würdest, könnte man drauf
> schauen.

Da wird es scheinbar mit "mangelnder Beratungsresistenz" immer
schwieriger.

Artur schrieb:
> Programmierer "meiner Klasse"(Über 70

von Wastl (hartundweichware)


Lesenswert?

Artur schrieb:
> So programmiere ich immer noch
> Hobbymäßig mit der alten Einrichtung / Umgebung.

.... und stopselt tage- und wochenlang vor sich hin anstatt
sich richtig helfen zu lassen - mit einem kompletten, nach-
vollziehbaren Code den man zur Verfügung stellt.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Artur schrieb:
> Die IDE wurde mir vor Jahren vom Arbeiskollegen in
> Frankfurt eingerichtet.

PS: Mittlerweile kommt die STM32CubeIDE mit einem simplen Installer. Da 
bekommt man mit wenigen Klicks ein aktuelles (!) funktionsfähiges 
Gesamtpaket und muss auch nix konfigurieren. Man hat sehr schnell ein 
Projekt für den gewünschten Controller angelegt, kann sich grafisch die 
Takt- und Pin-Konfiguration zusammenklicken und bekommt den 
entsprechenden Code generiert. Das kann sich jeder selbst einrichten.

von Wastl (hartundweichware)


Lesenswert?

Niklas G. schrieb:
> Man hat sehr schnell ein
> Projekt für den gewünschten Controller angelegt, kann sich grafisch die
> Takt- und Pin-Konfiguration zusammenklicken

Naja, das ist für einen "Anfänger" schon eine kleine Herausforderung
da es beim "Zusammenklicken" schon einige Sachen zu beachten gibt
die sich als kleine Fallstricke herausstellen können. Aber man
muss ja nicht die graphische Initialisierung wählen sondern kann
sich nach herkömmlicher Art sein Projekt in der CubeIDE zusammen-
stellen - einfach alle Sourcen in ein neues leeres Projekt herein-
kopieren. Das würde sich auch anbieten wenn der TO mal sein
komplettes Projekt posten würde.

Die CubeIDE zu verwenden ist auf jeden Fall empfehlenswert um von
der halbgaren Eclipse-Installation wegzukommen. Ja ich weiss,
Eclipse ist dann immer noch präsent ...

von Artur (arwar)


Angehängte Dateien:

Lesenswert?

Wastl schrieb:
> Niklas G. schrieb:
>
> Da wird es scheinbar mit "mangelnder Beratungsresistenz" immer
> schwieriger.
>
> Artur schrieb:
>> Programmierer "meiner Klasse"(Über 70

Da habt Ihr scheinbar gar nicht so unrecht :-)

Pas Projekt ist inzwischen "etwas" gröser geworden(siehe Bild). Ein Paar 
Verzeichnisse fehlen noch. Ich versuche den "Sieben Segment Display" mit 
einen "graphischen Display" zu ersetzen.

Würde es helfen die main(),  Display.c und die Display.h zur Verfühgung 
zu stellen?
Soll ich den Code direkt hier einfügen?
Oder ich kann auch das Projekt komplett mal zippen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Artur schrieb:
> Würde es helfen die main(),  Display.c und die Display.h zur Verfühgung
> zu stellen?

Und wenn dein Speicherzugriffsfehler woanders liegt?

Artur schrieb:
> Oder ich kann auch das Projekt komplett mal zippen.

Ja, oder auf GitHub stellen

von Rolf (rolf22)


Lesenswert?

Artur schrieb:
> Erst eine weitere Ergänzung der Tabellendefinition mit "static" hat mich
> weitergebracht
>
1
> "static const unsigned short Arial_7x10_Table[95][10] . . . "
2
>

Warum das so ist, erfährst du wahrscheinlich steht hier:
https://stackoverflow.com/questions/15235526/the-static-keyword-and-its-various-uses-in-c

von Wastl (hartundweichware)


Lesenswert?

Artur schrieb:
> Ich versuche den "Sieben Segment Display" mit
> einen "graphischen Display" zu ersetzen.

Nein. Sondern:
Du versuchst das "Sieben Segment Display" durch
ein "_graphisches_ Display" zu ersetzen.

von Wastl (hartundweichware)


Lesenswert?

Artur schrieb:
> komplette Tabelle am Anfang der  Main() eingetragen (95 Zeilen).
> Compiler hat sich "verschluckt"

Das ist mir im Nachhinen klar: die grosse Struct in Main anzulegen
sprengt die Grösse des Stacks die per default irgendwo festgelegt
wird.

"Grosse" Datenmengen sollte man immer Modul-global oder total
global anlegen, dann belasten sie nicht den Stack.

Hab ich überlesen dass das schon jemand erwähnt hat? Dann
sorry für die Verdoppelung .....

von Wastl (hartundweichware)


Lesenswert?

Artur schrieb:
> Die gesamte Tabelle ins "Display.h" verschoben

Das ist pöhse, das tut man nicht und es fällt einem irgendwann
auf die Füsse. Daten und Code in *.h Dateien tut man nicht.
Nein das tut man nicht! Bunkt.

von Rolf (rolf22)


Lesenswert?

Wastl schrieb:
> Du versuchst das "Sieben Segment Display" _durch_
> ein "_graphisches_ Display" zu ersetzen.

www.deppenleerzeichen.de

von Norbert (der_norbert)


Lesenswert?

Na? Entgleist es euch wieder?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Wastl schrieb:
> Das ist mir im Nachhinen klar: die grosse Struct in Main anzulegen
> sprengt die Grösse des Stacks die per default irgendwo festgelegt
> wird.

Naja weil Stack und .data beim Default Setup vom STM32 sich entgegen 
wachsen, sollte es effektiv keinen Unterschied machen... Besonders schön 
ist es aber wirklich nicht.

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Artur schrieb:
> weitere Ergänzung der Tabellendefinition mit "static" hat mich
> weitergebracht
>
> "static const unsigned short Arial_7x10_Table[95][10] . . . "
>
> Die gesamte Tabelle ins "Display.h" verschoben - geht auch :-)

Du hast offenbar keine Ahnung, was Du da tust.

Durch "static" beschränkst Du den Scope für die Tabelle auf die aktuelle 
Übersetzungseinheit. Wenn Du dann zusätzlich noch die Tabelle ins 
Display.h verschiebst, ist das ein Doppel-Eigentor.

Folge ist nämlich, dass die Tabelle damit für jede Übersetzungseinheit, 
in welcher Du Display.h inkludierst, noch einmal neu erzeugt wird. Wenn 
also ein Dutzend von C-Sources
1
#include "Display.h"
aufrufen, hast Du auch ein dutzendmal die Tabelle im Speicher - ob Flash 
oder auch RAM... siehe oben.

Mit Deinen Aktionen dokterst Du nur an den Symptomen, ohne den 
eigentlichen Fehler auszumerzen. Du hast höchstwahrscheinlich einen 
Buffer-Overflow für die Variable, die im Source vor Deiner 
Array-Definition liegt. (*1)

Beispiel:
1
#include <stdio.h>
2
#include <string.h>
3
4
char buffer[4];
5
int variable;
6
7
int main ()
8
{
9
    strcpy (buffer, "hello"); // Dieser Befehl überschreibt variable
10
11
    printf ("%d\n", variable);
12
}

(*1) Muss nicht zwingend so sein, je nach Compiler oder Optimierung kann 
die Reihenfolge der Variablen im RAM abweichen. Wenn man beide Variablen 
in eine Struct packt, dann passierts aber ziemlich sicher.

: Bearbeitet durch Moderator
von Harald K. (kirnbichler)


Lesenswert?

Warum eine Tabelle mit 8-Bit-Werten als short angelegt wird, wurde 
auch noch nicht beantwortet.

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.