Variable als static deklarieren

Gast #642252
Lesenswert?

Hallo zusammen,

ich deklariere innerhalb einer Funktion die Variable val_dyn als static:

void rot_decode (uint8_t)
{ uint8_t t_flag = 0;
  static uint8_t val_dyn;
       usw.

Diese Funktion wird von einer ISR aufgerufen, verändert aber keine 
Variable;
Optimierung im Makefile = 0 (sicherheitshalber (?)).
Benutzt werden WINAVR und avr-libc 1.4.3 sowie VMLAB zur Simulation.

Was passiert?
Übersetzung ok. ohne Fehlermeldungen und Warnungen; die Funktion 
arbeitet
einwandfrei, allerdings: val_dyn existiert nicht.

Beim Debuggen im 'single step' wird die Deklaration einfach 
übersprungen.

Kann mir jemand auf die Sprünge helfen? Was mache ich falsch?

(Hoffentlich habe ich die Situation ausreichend klar beschrieben).

Wolf
Gast #642268
Lesenswert?

Hallo Jörg,

ich hätte schreiben sollen "deklariert und definiert ...".

Natürlich wird die Variable innerhalb dieser Funktion benutzt, ich 
wollte nicht den Code der ganzen Funktion posten.
Also: val_dyn speichert einen über I2C-Bus gelesenen Wert bis zu einem 
erneuten Aufruf der Funktion.

Gruss

Wolf
#642294
Lesenswert?

Das wird wohl ein kleines Problem/Defizit des Debuggers sein. Statische 
Variable liegen ja nicht auf dem Stack, sondern im Datensegment. 
Eventuell kannst du sie sehen, wenn der Debugger eine Möglichkeit 
bietet, globale Variablen anzusehen. Der Name könnte dann aber entweder 
kryptisch oder sonstwie eindeutig gemacht sein, denn es können ja viele 
Funktionen existieren, die dieselbe statische Deklaration enthalten - 
die muß jeweils mit einer anderen Speicheradresse verknüpft sein.

Die lokale Gültigkeit von lokalen statischen Variablen wird einzig durch 
den Compiler erzwungen. Wenn man die Adresse so einer Variablen kennt, 
kann man sie jederzeit zugreifen - auch wenn sie lexikalisch gerade 
nicht gültig ist.

Bei dynamischen Variablen ist das ausgeschlossen, da dynamische 
Variablen nur existieren, wenn ein Stackframe der Funktion existiert, in 
der sie definiert sind - ist die Funktion rekursiv, dann können sogar 
mehrere Frames vorhanden sein, für jede Inkarnation eins.

Sieh dir mal das map-Listing des Linkers an. Dort müßten die Namen und 
Adressen aufgeführt sein.
Gast #642323
Lesenswert?

Danke für den Tipp.

<Das wird wohl ein kleines Problem/Defizit des Debuggers sein.>

Verwende ich AVR Studio statt VMLBab, ändert sich nichts!?

Im map-file finde ich:
  63:switches.c    **** uint8_t dg_flag = 0, t_flag = 0, temp;
 131                 .LM1-rot_decode
 132                 .LM1:
 133 0018 1B82          std Y+3,__zero_reg__
 134 001a 1A82          std Y+2,__zero_reg__

  64:switches.c    **** static uint8_t val_dyn; 
//enthält Wert der 1. Abfrage
  65:switches.c    ****

  66:switches.c    **** #define DG1_cw    0x81;
  67:switches.c    **** #define DG1_ccw  0x82;
  68:switches.c    **** #define DG2_cw    0x84;
  69:switches.c    **** #define DG2_ccw  0x88;
  70:switches.c    ****
  71:switches.c    ****   GICR &= ~(_BV(INT1));

Wenn ich das richtig interpretiere, existiert val_dyn nicht!!

Hier nochmals der Code (soweit relevant):

void rot_decode (uint8_t dg_stat[])
{

uint8_t dg_flag = 0, t_flag = 0, temp;
static uint8_t val_dyn; 
//enthält Wert der 1. Abfrage

#define DG1_cw    0x81;
#define DG1_ccw          0x82;
#define DG2_cw    0x84;
#define DG2_ccw          0x88;

  GICR &= ~(_BV(INT1));
....
....
  i2c_start(ENC_ADR + I2C_WRITE);    //IO-Expander abfragen
  temp = i2c_readNak();              //enthält Wert nach 1. Abfrage
  PAUSE_p(5);               //Prellzeit abwarten 
i2c_start(ENC_ADR + I2C_WRITE);    //IO-Expander erneut abfragen
        val_dyn = i2c_readNak();           //enthält gültigen Wert 
(dyn.)          i2c_stop();

(die letzten 6 Zeilen nur zum Verständnis)
#642351
Lesenswert?

Da val_dyn in den ASM-Fragmenten, die du gepostet hast, nicht
zugegriffen wird, sieht man nichts davon. Die Deklaration bewirkt nur,
daß der Compiler irdendwo im Datensegment den Platz dafür reserviert.
Dafür wird zur Laufzeit kein Code ausgeführt.

Such mal im ASM-Output des Compilers nach einer Stelle, an der val_dyn
gelesen, oder geschrieben wird. Dann kennst du den Namen, den der
Compiler dafür generiert hat. Damit kannst du dann evtl. auch im
Debugger darauf zugreifen.

> Im map-file finde ich:

Das ist nicht der map-File, sondern das ASM-Listing des Compilers.

Unter dem map-Listing versteht man eine Liste der Zuordnungen von 
Symbolnamen zu Speicheradressen. Es wird nicht vom Compiler erzeugt, 
sondern vom Linker.
Gast #642910
Lesenswert?

Finde nach 'Build' die Warnung
static variable adress beyond RAM limit:val_dyn ->.0x800331

Auch für statische Variable in anderen Funktionen erscheinen 
entsprechende Warnungen. Hatte ich bisher nicht beachtet ( :( ).

Was kann die Ursache hierfür sein und wie könnte eine Abhilfe aussehen?

Im map-File erscheint val_dyn mit Adresse 0x0080032e.

Wolf
Gast #643273
Lesenswert?

kbuchegg wrote:
>Der Flash ist nicht das Problem.
>Oder willst du deine Variablen nur auslesen?

Sollte mir eigentlich klar sein, sonst brauchte man ja wohl keine 
Variablen.

Speicherverbrauch lt. AVR Studio
   Data: 791 bytes (38.6% full)
   (.data + .bss +.noinit)


uhu wrote:
>Gibst du den richtigen Prozessortyp an?

ja, Atmega32
Gast #644550
Lesenswert?

Jörg wrote:

>Sieht aber so aus, als würde dein VMLAB nichts davon wissen.

Mag sein, die 'Ignoranz' bezüglich der staischen Variablen zeigt auch 
AVR Studio.
Welche Gründe dafür könnte es geben? Speicherbelegung für Daten und 
Programm scheiden m.E aus.

>Diese Ausschrift sieht nicht nach Compiler oder Linker aus.

Was meinst Du damit?
Gast #645694
Lesenswert?

Jörg wrote:

>static variable adress beyond RAM limit:val_dyn ->.0x800331

>Das sieht mir eher wie eine Meldung von VMLAB aus.

Stimmt; allerdings verwendet VMLAB den GNU C compiler genau so wie AVR 
Studio auch.

Da sich bisher für mich keine Alternativen zeigen: Gibt es die 
Möglichkeit, der statischen Variablen 'zwangsweise' eine Adresse im RAM 
zuzuweisen (ich möchte sie möglichst nicht global deklarieren)?


Florian wrote:

>Wenn der Code vollständig war (oben) und Deine statische Variable nur
>beschrieben und sonst nicht weiter verwendet wird, dann wird diese ggf.
>- zu Recht - wegoptimiert.

Würde ich ja verstehen, aber sie wird geschrieben und gelesen (s.u.):

    i2c_start(ENC_ADR + I2C_WRITE);    //IO-Expander abfragen
    temp = i2c_readNak();              //enthält Wert nach 1. Abfrage
    PAUSE_p(5);                        //Prellzeit abwarten
    i2c_start(ENC_ADR + I2C_WRITE);    //IO-Expander erneut abfragen
>>  val_dyn = i2c_readNak();           //enthält gültigen Wert
    i2c_stop();

Im weiteren Verlauf wird sie auch gelesen, z.B.
    if (val_dyn & 0x020)

BTW: Danke für die bisherige Hilfe.

Wolf
Moderator Persönliche Seite #645939
Lesenswert?

Wolf wrote:

>>Das sieht mir eher wie eine Meldung von VMLAB aus.

> Stimmt; allerdings verwendet VMLAB den GNU C compiler genau so wie
> AVR Studio auch.

Trotzdem ist die Meldung von VMLAB, nicht vom Compiler oder Linker.
VMLAB hat in der Analyse der Objektdatei festgestellt, dass die
Variable auf deinem Zielprozessor gar nicht im RAM untergebracht
worden ist.

> Da sich bisher für mich keine Alternativen zeigen: Gibt es die
> Möglichkeit, der statischen Variablen 'zwangsweise' eine Adresse im
> RAM zuzuweisen (ich möchte sie möglichst nicht global deklarieren)?

Das hilft doch nichts.  Du hast einfach keinen RAM mehr, zumindest
laut Meinung von VMLAB.  Offenbar geht hier VMLAB von einem anderen
Controller aus als der Compiler, oder es hat einen Bug und ist der
Meinung, der benutzte Controller hätte weniger RAM als er wirklich
hat.
Gast #658374
Lesenswert?

vieleicht hilft es, die variable mit einem vernünftigen Wert zu 
initialisieren.:
1
void rot_decode (uint8_t)
2
{ uint8_t t_flag = 0;
3
  static uint8_t val_dyn = 0;
      usw.

keine angst, per C-Standard wird diese Initialisiereung genau einmal 
ausgeführt und nicht
für jeden Aufruf.

HTH
      -krono
Gast #660153
Lesenswert?

Jörg Wunsch wrote:

>> keine angst, per C-Standard wird diese Initialisiereung genau einmal
>> ausgeführt und nicht
>> für jeden Aufruf.
>
> Quatsch.  Die Initialisierung einer lokalen Variablen wird bei
> jedem Aufruf vorgenommen, und statische Variablen werden per C-Standard
> ohnehin mit 0 initialisiert, wenn nichts anderes angegeben ist.

einer lokalen variable ja.
aber nicht bei einer statischen lokalen variable.
ansonsten wuerde dass hier nicht funktionieren.

(btw: c89 heisst, das ganze wird mit einem ANSI-C Compiler gebaut)
1
Script started on Sat Sep 22 17:19:30 2007
2
tppb:/tmp tobias$ cat static.c
1
#include <stdio.h>
2

3
void foo(void)
4
{
5
    static int var = 42;
6
    printf("%d\n", var++);
7
}
8

9

10
int main(void)
11
{
12
    foo();
13
    foo();
14
    foo();
15
    foo();
16
    return 0;
17
}
1
tppb:/tmp tobias$  c89 -o static static.c 
2
tppb:/tmp tobias$ ./static 
3
42
4
43
5
44
6
45
7
tppb:/tmp tobias$ exit
8

9
Script done on Sat Sep 22 17:20:08 2007

hth,
      -krono
#660209
Lesenswert?

krono wrote:
> einer lokalen variable ja.
> aber nicht bei einer statischen lokalen variable.
> ansonsten wuerde dass hier nicht funktionieren.

Eine lokale statische C-Variable wird nur einmal bei Programmstart 
initialisiert. (C++ initialisiert sie, wenn sie zum ersten mal sichtbar 
wird.)

Die Eigenschaft 'lokal' wird bei statischen Variablen nur vom 
Scopemechanismus des Compilers erzwungen. Die Variable selbst lebt von 
Programmstart bis zum Ende, ist aber nur in dem Block sichtbar, in dem 
sie definiert ist.
Gast #660226
Lesenswert?

Uhu Uhuhu wrote:

> Eine lokale statische C-Variable wird nur einmal bei Programmstart
> initialisiert. (C++ initialisiert sie, wenn sie zum ersten mal sichtbar
> wird.)
>
> Die Eigenschaft 'lokal' wird bei statischen Variablen nur vom
> Scopemechanismus des Compilers erzwungen. Die Variable selbst lebt von
> Programmstart bis zum Ende, ist aber nur in dem Block sichtbar, in dem
> sie definiert ist.

hab ich nicht bezweifelt.
(selfquote)
keine angst, per C-Standard wird diese Initialisiereung genau einmal
ausgeführt und nicht
für jeden Aufruf.
(/selfquote)
genau ein mal. beim "betreten" von main.
Moderator Persönliche Seite #660343
Lesenswert?

krono wrote:

> mein punkt war halt das einmalige intialisieren dieser variablen,
> die ja (für ungeübte) nach lokaler variable aussieht.

Und mein Punkt war, dass du deine Aussage ,,wird nur einmal erledigt''
unter ein Stück Code mit zwei verschiedenen Initialisierungen
gesetzt hast, von denen eine wirklich nur einmal erfolgt, die andere
aber (automatische Variable) bei jedem Funktionseintritt.  Zudem war
die Initialisierung, auf die sich der Kommentar bezog (nämlich die
der statischen Variablen) völlig überflüssig, da sie der ohnehin
vom Compiler/Laufzeitsystem bereits vorgenommenen Initialisierung
aller statischer Objekte auf 0 entspricht.

Damit ist auch klar, dass dein Vorschlag, die Variable ,,mit einem
vernünftigen Wert zu initialisieren'', dem OP keinerlei Änderung
des Verhaltens bringen wird.  Der damit generierte Objektcode ist
nämlich letztendlich identisch.  (GCC erkennt mittlerweile, dass
eine Initialisierung eines statischen Objekts mit 0 bzw. NULL der
default-Initialisierung entspricht, und schiebt dadurch die Variable
nicht mehr aus dem .bss ins .data, wie er das früher noch gemacht
hat.)
Gast #660371
Lesenswert?

das mit den 2 deklarationen kam daher, dass ich nur den "vorgegebenen" 
code geaendert habe.

und die initialisierung statischer variablen auf 0 war mir bis dato 
nicht bekannt.

ist ja auch eigentlich fuers problem irrelevant.
ich wurde mich fragen, ob dass ueberhaupt hülfe.
Gast #662154
Lesenswert?

krono wrote:

> vieleicht hilft es, die Variable mit einem vernünftigen Wert zu
> initialisieren.:

Habe ich ich schon früher versucht, erwartungsgemäss ohne Erfolg.

Nach wie vor bleibt für mich die zentrale Frage, wie ich AVR Studio 
(WINAVR) dazu bewege, meinen Code mit (lokalen) statischen Variablen zu 
compilieren und zu linken, um ihn mit STK500 zu testen.

Eine globale Deklaration möchte ich vermeiden; jedes bessere C-Handbuch 
weist darauf hin.
Gast #662302
Lesenswert?

inzwischen hat sich zu diesem Thema vielerlei angesammelt, vielleicht 
hast Du es übersehen - meine Beiträge v. 29.8.07 und 1.9.07.
STK500 ist für mich eine komfortable Hw-Plattform mit einiger Peripherie 
wie LEDs, Schalter, UART und hat m.E. nichts mit den geschilderten 
Schwierigkeiten zu tun.
Gast #662798
Lesenswert?

Da ich meinen Code inzwischen verändert/erweitert habe, muss ich 
versuchen, den damaligen Stand zu restaurieren, werde mich aber auf 
WinAVR, AVRStudio (und STK500) beschränken und VMLAB zunächst ausser 
acht lassen.

Bis dahin Dank für bisherige Hilfe.

Wolf
Gast #683191
Lesenswert?

wegen anderer Prioritäten habe ich erst jetzt das Problem wieder 
aufgreifen können.

Ergebnis: Mit AVRStudio und STK500 als Target wird eine Variable als 
static ohne Probleme akzeptiert und so behandelt wie erwartet.

VMLAB verarbeitet tatsächlich <static> nicht richtig.

Danke nochmals.

Wolf
Gast #683384
Lesenswert?

>VMLAB verarbeitet tatsächlich <static> nicht richtig.

Lokale static-variablen lassen sich im watch-Fenster schon ansehen, 
allerdings nicht im scope der zugehörigen Funktion, sondern im scope von 
main.

Oliver

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren