Forum: Compiler & IDEs Frage zu static bei C nicht C++


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 Thomas Z. (usbman)


Lesenswert?

Ich hab ein paar Fragen zur Bedeutung von static in C

Mein bisheriges Verständnis von static bezieht sich vorwiegend auf die 
Verwendung in lokalen Variablen von Funktionen. Dort ist es einfach so 
dass die Variable nur lokal in der Funktion existiert, tatsächlich aber 
global angelegt ist ohne Sichtbarkeit in anderen Funktionen oder 
Modulen. Die Variable behält also Ihren Wert zwischen den 
Funktionsaufrufen.
Soweit ist noch alles klar.

Nun sehe ich immer wieder folgende Deklaration in Funktionen die ich 
nicht genau zuordnen kann
1
void foo(void)
2
{
3
   static uint8_t test = 0;
4
   ....
5
}
was bewirkt das genau? test wird doch bei jedem Aufruf auf 0 gestzt 
oder? static hätte also keinerlei Wirkung?

Bonusfrage: Was macht static bei einer Funktionsdeklaration.

Ich hab natürlch schon etwas Literatur gewälzt, aber bis jetzt noch 
keine zufriedenstellende Erklärung gefunden.

Kann mir jemand auf die Sprünge helfen?

von Klaus W. (mfgkw)


Lesenswert?

Thomas Z. schrieb:
> Nun sehe ich immer wieder folgende Deklaration in Funktionen die ich
> nicht genau zuordnen kannvoid foo(void)
> {
>    static uint8_t test = 0;
>    ....
> }
> was bewirkt das genau? test wird doch bei jedem Aufruf auf 0 gestzt
> oder? static hätte also keinerlei Wirkung?

Die Variable test existiert nur einmal pro Programm (bereits bei Start 
von main(), nicht erst ab dem Aufruf von kannvoid()) und wird dabei 
einmalig mit 0 initialisiert - nicht bei jedem Aufruf.

von Klaus W. (mfgkw)


Lesenswert?

In C++ wäre es übrigens praktisch gleich, auch wenn du nicht danach 
fragst, sorry.

Da gibt es nur eine kleine Nuance, die man nur bei Objekten einer Klasse 
bemerken wird in der Regel:
Die Initialisierung findet beim ersten Aufruf der Funktion statt.
Der Konstruktor eines solchen static-Objekts in einer Funktion wird also 
überhaupt nur dann ausgeführt, wenn die Funktion erstmalig aufgerufen 
wird - nicht bei Programmstart.

: Bearbeitet durch User
von A. S. (achs)


Lesenswert?

Thomas Z. schrieb:
> test wird doch bei jedem Aufruf auf 0 gestzt oder

Nein. Initialisiert wird bei static nur einmal.

Static begrenzt immer nur die Sichtbarkeit (wo man zugreifen kann) auf 
die umschließende Klammer { } bzw wenn direkt im C-File, auf das C-File. 
Die Variablen (oder Funktionen) sind aber immer dauerhaft, also nicht 
auf dem Stack.

von Klaus W. (mfgkw)


Lesenswert?

Thomas Z. schrieb:
> Bonusfrage: Was macht static bei einer Funktionsdeklaration.

Dasselbe wie jedes andere static außerhalb von Funktionen:
Der Name (hier der Name der Funktion) ist nur in diesem Quelltext 
sichtbar und nicht über den Linker aus anderen Modulen erreichbar.

Also eine dateilokale Funktion.

von Thomas Z. (usbman)


Lesenswert?

ok vielen Dank erst mal. Ich muss aber nochmal nachhaken...

Dann ist es doch egal ob in der Funktion schreibe
static unt8_t test; oder eben static unt8_t test=0; in beiden Fällen 
wird das Laufzeitsystem die Variable vor dem SystemStart auf 0 setzen 
oder?

Zu static bei Funktionen:
die sind doch sowieso erst mal nur im lokalen File sichtbar und können 
in andern Files nicht afgerufen werden. Das ist ja dann nur etwas 
syntaktischer Zucker oder?

von Klaus W. (mfgkw)


Lesenswert?

Thomas Z. schrieb:
> Dann ist es doch egal ob in der Funktion schreibe
> static unt8_t test; oder eben static unt8_t test=0; in beiden Fällen
> wird das Laufzeitsystem die Variable vor dem SystemStart auf 0 setzen
> oder?

Ich bin mir gerade nicht sicher. Aber ich glaube, wenn du nicht =0 
initialisierst, ist vielleicht der Inhalt nicht garantiert.
Auf jeden Fall ist es guter Stil, hinzuschreiben womit man initialisiert 
haben möchte - das drückt aus, was man will.

von (prx) A. K. (prx)


Lesenswert?

Klaus W. schrieb:
> Aber ich glaube, wenn du nicht =0
> initialisierst, ist vielleicht der Inhalt nicht garantiert.

Doch, ist er.

von Klaus W. (mfgkw)


Lesenswert?

Thomas Z. schrieb:
> Zu static bei Funktionen:
> die sind doch sowieso erst mal nur im lokalen File sichtbar und können
> in andern Files nicht afgerufen werden. Das ist ja dann nur etwas
> syntaktischer Zucker oder?

Nein, ist es nicht.

Wenn du nicht static schreibst, kann in jedem anderen Quelltext des 
Programms jemand deine Funktion als extern deklarieren und aufrufen:
1
extern int f();
2
...
3
    i = f();

Der Linker ruft dann die
1
int f()
2
{
3
   ...
4
}
auf.
Ohne static heißt also: Symbol exportieren.

Mit static:
1
static int f()
2
{
3
   ...
4
}
kannst du in anderen Quelltexten machen was, du willst - du kommst an 
die Funktion nicht ran.

: Bearbeitet durch User
von Thomas Z. (usbman)


Lesenswert?

Klaus W. schrieb:
> kannst du in anderen Quelltexten machen was, du willst - du kommst an
> die Funktion nicht ran.

Danke das wars was mir gefehlt hat. So ergibt das auch einen Sinn.

von (prx) A. K. (prx)


Lesenswert?

Es gibt einen bei Mikrocontrollern effektiven Unterschied zwischen 
expliziter und impliziter Initalisierung, egal ob static oder external 
scope. Explizite Initialisierung kostet Platz im Flash von 
Microcontrollern, wobei das beim Wert 0 vom Entwicklungssystem abhängen 
kann. GCC behandelt explizite Initialisierung mit 0 genau wie implizite, 
aber das muss nicht überall so sein.

von Klaus W. (mfgkw)


Lesenswert?

(prx) A. K. schrieb:
> Klaus W. schrieb:
>> Aber ich glaube, wenn du nicht =0
>> initialisierst, ist vielleicht der Inhalt nicht garantiert.
>
> Doch, ist er.

Ja, du hast recht - laut K&R wird eine lokale static zu 0 initialisiert, 
wenn man nichts anderes schreibt.

(Trotzdem empfehle ich es, explizit zu schreiben)

von Thomas Z. (usbman)


Lesenswert?

(prx) A. K. schrieb:
> Es gibt einen bei Mikrocontrollern effektiven Unterschied zwischen
> expliziter und impliziter Initalisierung, egal ob static oder external
> scope. Explizite Initialisierung kostet Platz im Flash von
> Microcontrollern, wobei das beim Wert 0 vom Entwicklungssystem abhängen
> kann. GCC behandelt explizite Initialisierung mit 0 genau wie implizite,
> aber das muss nicht überall so sein.

Genau deshalb hab ich hier noch mal nachgefragt. Ich debugge im Moment 
ein Binary wo ich mir einige Konstrukte nicht erklären kann (konnte).
Mit der static Geschichte und einem unwissenden C only Programmierer 
ergeben die InitTables die ich im Binary sehe auf einmal Sinn.

Falls es interessiert, es geht um ein Keil c51 binary.

: Bearbeitet durch User
von A. S. (achs)


Lesenswert?

Thomas Z. schrieb:
> Danke das wars was mir gefehlt hat. So ergibt das auch einen Sinn.

Mit static kommt nicht nur niemand dran: es erlaubt in mehreren Files 
Funktionen oder Variablen gleichen Namens zu haben:

Du kannst in jedem C-File ein static int initialized; haben oder ein 
static void f(void);

Das ist hilfreich wenn Module gleichartig aufgebaut sind.

von Thomas Z. (usbman)


Lesenswert?

A. S. schrieb:
> Mit static kommt nicht nur niemand dran: es erlaubt in mehreren Files
> Funktionen oder Variablen gleichen Namens zu haben:
>
> Du kannst in jedem C-File ein static int initialized; haben oder ein
> static void f(void);

danke das würde ich persönlich aber nicht machen...
Das ha ja schon was von c++ :-)

von Gerald K. (geku)


Angehängte Dateien:

Lesenswert?

Eine **static**  deklarierte Variable wird nicht am Stack abgelegt.

Der Wert bleibt nach dem Verlassen der Funktion, im Gegensatz zur 
lokalen Variablen ohne **static** , erhalten.

Eine Variable gleicher Deklaration mit gleichem Namen in einer anderen 
Funktion ist eine neue Variable

Dieses Verhalten zeigt das beiliegende Programm:
1
pi@test:~/test $ ./a.out 5                                                                 
2
&a in abc=135216
3
&a in xyz=135220
4
a  in xyz= 0
5
a  in abc= 5
6
pi@test:~/test $

von Gerald K. (geku)


Angehängte Dateien:

Lesenswert?

Verhalten der lokalen static Variable **a** im Vergleich zur lokalen 
Variablen **b** beim rekursiven Aufruf der Funktion mit der static 
Variablendeklaration:
1
pi@test:~/test $ ./a.out 56789
2
*&a,*&b in abc *135220=     56789,         *2127717716=     56789
3
*&a,*&b in abc *135220=       5678,         *2127717668=       5678
4
*&a,*&b in abc *135220=         567,          *2127717620=         567
5
*&a,*&b in abc *135220=           56,           *2127717572=           56
6
*&a,*&b in abc *135220=             5,           *2127717524=             5
7
8
a=5 b=56789
9
pi@test:~/test $

**Unterschied** :
 - die lokale static Variable a ist während der Rekursion immer die 
gleiche Variable, am Ende gilt der Wert der tiefsten Rekusion
- die normale locale Variable b wird bei jedem erneuten rekursiven 
Aufruf neu am Stack angelegt, am Ende gilt der Wert des ersten Aufrufes

Im Anhang das Programm.

: Bearbeitet durch User
von A. S. (achs)


Lesenswert?

Thomas Z. schrieb:
> danke das würde ich persönlich aber nicht machen...
> Das ha ja schon was von c++ :-)

?? Kapselung ist bei C genauso wichtig wie bei C++. Lokale Funktionen, 
die immer das gleiche zu tun, unterschiedlich zu benennen, wäre so, als 
würde man den Schleifenzähler i in verschiedenen Blöcken unterschiedlich 
benennen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

(prx) A. K. schrieb:
> Explizite Initialisierung kostet Platz im Flash von Microcontrollern,
> wobei das beim Wert 0 vom Entwicklungssystem abhängen kann.

Ich würde sagen: kann Platz kosten. Bei GCC (wie du schon festgestellt 
hast) war das letztmalig in Version 2.95 so, seither behandelt er das 
gleich. Übrigens unabhängig von Mikrocontroller oder nicht, auch "ganz 
normale" PC-Programme waren früher davon betroffen und haben 
entsprechend Platz in .data (und damit in der ELF-Datei) reserviert.

von A. S. (achs)


Lesenswert?

Gerald K. schrieb:
> Eine Variable gleicher Deklaration mit gleichem Namen in einer anderen
> Funktion ist eine neue Variable

oder anderer Block. Egal ob parallel, nacheinander (üblich bzw. normal) 
oder verschachtelt (legal, aber fehlerträchtig).

von (prx) A. K. (prx)


Lesenswert?

Jörg W. schrieb:
> C-Programme waren früher davon betroffen und haben
> entsprechend Platz in .data (und damit in der ELF-Datei) reserviert.

Natürlich. Nur spielt das auf Disk eine wesentlich geringere Rolle als 
im mitunter knappen Flash.

von Gerald K. (geku)


Lesenswert?

Thomas Z. schrieb:
> Bonusfrage: Was macht static bei einer Funktionsdeklaration.

Die Funktion ist im nur in c-Modul sichtbar in dem sie definiert wurde. 
Selbst eine Prototypdeklaration in einen anderen c-Modul veranlasst den 
Linker nicht die static Funktion zu verwenden.

von Gerald K. (geku)


Lesenswert?

Beitrag "Re: Frage zu static bei C nicht C++"

Gerald K. schrieb:
> Unterschied :
>
> die lokale static Variable a ist während der Rekursion immer die gleiche
> Variable, am Ende gilt der Wert der tiefsten Rekusion
> die normale locale Variable b wird bei jedem erneuten rekursiven Aufruf
> neu am Stack angelegt, am Ende gilt der Wert des ersten Aufrufes
>
> Im Anhang das Programm.

Die gleichzeitige Verwendung einer Funktion im Backgrund und in einer 
Interruptroutine bzw. zwei Threads mit einer static Variable führt zu 
einer Wechselwirkung dieser Variablen. Bei reinen lokalen Variablen 
besteht diese Problem nicht, da jede Variable in einem eigenen 
Stackbereich sitzt.

: Bearbeitet durch User
von DPA (Gast)


Lesenswert?

Das mit den threads kann man mit thread_local lösen:
https://en.cppreference.com/w/c/thread/thread_local

von dfIas (Gast)


Lesenswert?

Klaus W. schrieb:
> (prx) A. K. schrieb:
>> Klaus W. schrieb:
>>> Aber ich glaube, wenn du nicht =0
>>> initialisierst, ist vielleicht der Inhalt nicht garantiert.
>> Doch, ist er.
> Ja, du hast recht - laut K&R wird eine lokale static zu 0 initialisiert,
> wenn man nichts anderes schreibt.
> (Trotzdem empfehle ich es, explizit zu schreiben)
Im VS wird platterdings gemeckert, wenn man nicht explizit initialisiert 
('local variable is not initialized' trotz 'static'). Der Meldung nach 
gehe ich davon aus, dass der Fallback auf Null nicht mehr gilt. Ob das 
seit ISO C++17 verlangt wird - k. A. Früher war halt alles einfacher 
(und mehr Lametta).

von (prx) A. K. (prx)


Lesenswert?

Hast du ein Beispiel, in dem das auftritt, und die Meldung dazu?

: Bearbeitet durch User
von Thomas R. (r3tr0)


Lesenswert?


von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Klaus W. schrieb:
> (Trotzdem empfehle ich es, explizit zu schreiben)

Mit welcher Begründung?

Wenn du der implizierten Initialisierung nicht trauen kannst, warum 
solltest du der expliziten dann trauen können?

dfIas schrieb:
> Der Meldung nach gehe ich davon aus, dass der Fallback auf Null nicht
> mehr gilt.

Ich gehe der Meldung nach davon aus, dass der Compiler einen an der 
Waffel hat.

Warnungen werden durch den C-Standard nicht geregelt, aber die implizite 
Initialisierung statischer Variablen auf 0 gibt es zumindest seit dem 
ersten (pre-ANSI) K&R-Buch.

von Klaus W. (mfgkw)


Lesenswert?

Jörg W. schrieb:
> Wenn du der implizierten Initialisierung nicht trauen kannst, warum
> solltest du der expliziten dann trauen können?

Wegen der Lesbarkeit.

Schreibt man die Initialisierung explizit hin, sieht man klar ohne 
Nachdenken, daß die Variable einen definierten Startwert hat und daß der 
Schöpfer (m/w/d) das so will.

Dabei geht es nicht darum, ob die implizite Initialisierung 
funktioniert.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Klaus W. schrieb:
> Schreibt man die Initialisierung explizit hin, sieht man klar ohne
> Nachdenken, daß die Variable einen definierten Startwert hat und daß der
> Schöpfer (m/w/d) das so will.

Gut.

Ich bin allerdings ein Freund davon, Variablen nur dann zu 
initialisieren, wenn es unbedingt nötig ist, weil das (im nicht-"static" 
Fall) potenzielle Warnungen verhindert, die einen auf Fehler hinweisen 
können ("may be used uninitialized" obwohl man eigentlich der Meinung 
war, dass man überall passend Werte gesetzt hat).

von P. S. (namnyef)


Lesenswert?

Klaus W. schrieb:
> (Trotzdem empfehle ich es, explizit zu schreiben)
Sehe ich auch so. So ist die Intention klarer. Und nicht jeder, der den 
Code wartet, weiß direkt aus dem Stegreif, dass static Variablen 
implizit zu 0 initialisiert werden.
Viele Coding-Standards schreiben schließlich auch die explizite 
Initialisierung von static Variablen vor. Und viele Tools für statische 
Code-Analyse bieten entsprechende Überprüfungen.

Zusammenfassung zum Keyword static:
- Static Variablen innerhalb einer Funktion behalten ihren Wert während 
mehrmaliger Aufrufe der Funktion.
- Static Variablen außerhalb einer Funktion sind nur innerhalb ihres 
Moduls sichtbar.
- Static Variablen werden nur einmalig initialisiert (entweder explizit 
oder implizit zu 0).
- Static deklarierte Funktionen sind nur innerhalb ihres Moduls 
sichtbar.

von Rolf M. (rmagnus)


Lesenswert?

In Funktionen gibt es zwei Arten von Variablen, nämlich static (für 
"static storage duration") und auto (für "automatic storage duration"). 
Wenn man keins der beiden Schlüsselwörter angibt, wird implizit auto 
angenommen.

static storage duration bedeutet, dass die Variable über die gesamte 
Programmlaufzeit existiert.
automatic storage duration bedeutet, dass die Variable jedes mal beim 
Erreichen ihrer Definiton neu erzeugt und beim Verlassen des Blocks, in 
dem sie definiert ist, automatisch wieder zerstört wird.

: Bearbeitet durch User
von Dennis S. (eltio)


Lesenswert?

dfIas schrieb:
> Ob das
> seit ISO C++17 verlangt wird - k. A.

Es gibt keinen C-Standard der in irgendeiner Weise C++17 genannt wird.

von Gerald K. (geku)


Lesenswert?

P. S. schrieb:
> Sehe ich auch so. So ist die Intention klarer

Wenn man ein **static** Variable zwischen den Funktionsaufrufen 
überleben lassen will,dann Initalisierung der Variablen 
kontraproduktiv. Die Variable wird bei jedem  Aufrauf neu initalisiert.

**Testprogramm** :
1
int b;
2
3
void test(void)
4
{
5
        static int a;
6
7
        printf("static *&a %d=%d, gobal *&b %d=%d\r\n",&a,a,&b,b);
8
9
}
10
11
int main(int argc, char* argv[])
12
{
13
        test();
14
}

**Ergebnis** :
1
pi@test:~/test $ ./a.out
2
static *&a 135212=0, gobal *&b 135216=0
3
pi@test:~/test $

Das Segment der globalen Variablen wird vor Aufruf des Programmes mit 
**0en** gefüllt.
Die lokale **static** Variable befindet sich im gleichen Segment (beim 
Testprogramm liegt b unmittalbar nach a), als darf man davon ausgehen, 
dass sie auch vorinitalisiert ist.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Dennis S. schrieb:
> dfIas schrieb:
>> Ob das
>> seit ISO C++17 verlangt wird - k. A.
>
> Es gibt keinen C-Standard der in irgendeiner Weise C++17 genannt wird.

Es gibt allerdings einen, der C17 genannt wird. Mich würde es aber sehr 
überraschen, wenn dort eine solche Warnung gefordert würde (und das gilt 
für C und für C++).

Gerald K. schrieb:
> P. S. schrieb:
>> Sehe ich auch so. So ist die Intention klarer
>
> Wenn man ein **static** Variable zwischen den Funktionsaufrufen
> überleben lassen will,dann Initalisierung der Variablen
> kontraproduktiv. Die Variable wird bei jedem  Aufrauf neu initalisiert!

Quatsch.

Gerald K. schrieb:
> Das Segment der globalen Variablen wird vor Aufruf des Programmes mit
> **0en** gefüllt.

Nicht "das Segment der globalen Variablen", sondern das .BSS-Segment. 
Das ist das Segement für alle Variablen mit "static storage duration", 
die (implizit oder explizit) mit 0 initialisiert wurden.

> Die lokalen **static** Variablen befinden sich im gleichen Segment,

Sofern sie ebenfalls (implizit oder explizit) mit 0 initialisiert 
wurden.

> als darf man davon ausgehen, dass sie auch vorinitalisiert sind.

Allein auf Basis der Adresse kann man nicht davon ausgehen. Besser ist 
es, als Basis die entsprechende Regel des C-Standards zu nehmen, die das 
so vorschreibt.

von Gerald K. (geku)


Lesenswert?

Rolf M. schrieb:
> Quatsch

Da lag ich falsch.
1
void test(int input)
2
{
3
        static int a=0;
4
5
        if (input>10) a=input;
6
7
        printf("static *&a %d=%d\r\n",&a,a);
8
9
}
10
11
int main(int argc, char* argv[])
12
{
13
        test(4711); // 1. Aufruf
14
        test(4);        // 2. Aufruf
15
}

**Ergebnis** :
1
pi@test:~/test $ ./a.out
2
static *&a 135212=4711
3
static *&a 135212=4711
4
pi@test:~/test $

Wenn der Code "static int a=0;" nach dem Funktionsheader steht, darf 
nicht davon ausgegangen werden, dass dieser dort jedesmal aufgerufen 
wird.

Wieder einmal was dazu gelernt. Danke!

: Bearbeitet durch User
von Dirk B. (dirkb2)


Lesenswert?

Gerald K. schrieb:
> printf("static *&a %d=%d, gobal *&b %d=%d\r\n",&a,a,&b,b);

Der Formatspecifier für Pointer ist %p.
Das weiß auch der Compiler und warnt dann - wenn man ihn läßt.
Schalt mal die Warnungen beim Compiler auf Maximum.

von A. S. (achs)


Lesenswert?

Klaus W. schrieb:
> Schreibt man die Initialisierung explizit hin, sieht man klar ohne
> Nachdenken, daß die Variable einen definierten Startwert hat und daß der
> Schöpfer (m/w/d) das so will.

Dann solltest Du es zumindest auf die Fälle beschränken, wo die 0 auch 
genau so gewollt ist und nicht einfach nur ein Default. Also nicht in 
Code, der beim ersten Aufruf diese variable mit einem zur compilezeit 
unbekannten Wert überschreibt.

P. S. schrieb:
> Und nicht jeder, der den Code wartet, weiß direkt aus dem Stegreif,
> dass static Variablen implizit zu 0 initialisiert werden

Mit dem Argument ist aber auch kein *p++ oder !a && b möglich.

: Bearbeitet durch User
von A. S. (achs)


Lesenswert?

Thomas R. schrieb:
> Hier wunderbar erklärt:

Bei Aussagen wie

> Aber Achtung: Statische Variablen müssen schon bei ihrer Deklaration 
initialisiert werden!

Ist das ganze aber eher ... unzuverlässig. Im Ernst: wie soll ich da 
erkennen, was C ist und was der Autor meint.

von Rolf M. (rmagnus)


Lesenswert?

Dirk B. schrieb:
> Gerald K. schrieb:
>> printf("static *&a %d=%d, gobal *&b %d=%d\r\n",&a,a,&b,b);
>
> Der Formatspecifier für Pointer ist %p.

Allerdings für Pointer auf void. Man muss also (void*)&a draus machen, 
denn:

> Das weiß auch der Compiler und warnt dann - wenn man ihn läßt.

Beitrag #6728454 wurde vom Autor gelöscht.
von Klaus W. (mfgkw)


Lesenswert?

Rolf M. schrieb:
> Allerdings für Pointer auf void. Man muss also (void*)&a draus machen,

nein, muß man nicht.

Jede Adresse lässt sich ohne Gemecker in eine void* konvertieren.
Und mit printf kann man ohne cast jede Adresse mit %p ausgeben.

von Rolf M. (rmagnus)


Lesenswert?

Gerald K. schrieb im Beitrag #6728454:
> Dirk B. schrieb:
>> Der Formatspecifier für Pointer ist %p.
>> Das weiß auch der Compiler und warnt dann - wenn man ihn läßt.
>
> Als Text im printf() immer zulässig. Warum nicht?

Weil Pointer und int nicht unbedingt die selbe Größe haben müssen. Auf 
einem üblichen 64-Bit-System ist z.B. ein Pointer doppelt so groß wie 
ein int. Das heißt je nach System, dass im schlimmsten Fall hier auf 
Speicher zugegriffen wird, der dafür nicht vorgesehen ist, im besten 
Fall wird dir nur die Hälfte des Zeigerwerts angezeigt. Außerdem können 
Pointer je nach System ein eigenes Darstellungsformat haben.

> Ich habe immer alle Warnungen eingeschaltet.

Dann solltest du da eigentlich auch eine bekommen.

von Rolf M. (rmagnus)


Lesenswert?

Klaus W. schrieb:
> Rolf M. schrieb:
>> Allerdings für Pointer auf void. Man muss also (void*)&a draus machen,
>
> nein, muß man nicht.
>
> Jede Adresse lässt sich ohne Gemecker in eine void* konvertieren.

Ja, aber bei variadischen Funktionen muss man das explizit tun, weil das 
dort implizit nicht möglich ist.

> Und mit printf kann man ohne cast jede Adresse mit %p ausgeben.

Das muss nicht gezwungenermaßen so sein. Pointertypen dürfen durchaus 
unterschiedlich groß sein. Es ist nur garantiert, dass ein void* jeden 
Wert einees Objektzeigers aufnehmen kann.
Mein gcc warnt übrigens auch:
1
#include <stdio.h>
2
3
int main()
4
{
5
    int a = 3;
6
    int* b = &a;
7
    printf("%p\n", b);
8
}

Ausgabe von gcc printpointer.c -pedantic:
1
printpointer.c: In function ‘main’:
2
printpointer.c:7:14: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int *’ [-Wformat=]
3
    7 |     printf("%p\n", b);
4
      |             ~^     ~
5
      |              |     |
6
      |              |     int *
7
      |              void *
8
      |             %ls

von (prx) A. K. (prx)


Lesenswert?

Klaus W. schrieb:
> Rolf M. schrieb:
>> Allerdings für Pointer auf void. Man muss also (void*)&a draus machen,
>
> nein, muß man nicht.
>
> Jede Adresse lässt sich ohne Gemecker in eine void* konvertieren.
> Und mit printf kann man ohne cast jede Adresse mit %p ausgeben.

Nur dass der Compiler bei einer Funktion mit variabler Argumentliste wie 
printf keine Ahnung hat, dass er den Pointer konvertieren soll. 
Verschiedene Arten von Pointern können unterschiedliche interne 
Repräsentationen haben, auch bei der Länge.

Funktionen wie printf sind insoweit besonders, als der Compiler bei 
ihnen den Formatstring mit den Parametertypen abgleicht. Das ist aber 
ein Luxus von gcc, kein Sprachbestandteil.

: Bearbeitet durch User
von Klaus W. (mfgkw)


Lesenswert?

Rolf M. schrieb:
> ...
>> Und mit printf kann man ohne cast jede Adresse mit %p ausgeben.
>
> Das muss nicht gezwungenermaßen so sein. Pointertypen dürfen durchaus
> unterschiedlich groß sein. Es ist nur garantiert, dass ein void* jeden
> Wert einees Objektzeigers aufnehmen kann.
> Mein gcc warnt übrigens auch:#include <stdio.h>
> ...

ja, ok.

(Aber doch schon sehr pedantisch...
Ein System, bei dem Adressen unterschiedlich lang sind, hatte ich noch 
nicht in der Mache, und werde sowas auch nie anfassen hoffe ich.)

von (prx) A. K. (prx)


Lesenswert?

Klaus W. schrieb:
> Ein System, bei dem Adressen unterschiedlich lang sind, hatte ich noch
> nicht in der Mache, und werde sowas auch nie anfassen hoffe ich.

Dann hast du noch nie mit AVRs gearbeitet, wirst sie auch nie anfassen:
1
int              *p; int p_len = sizeof(p); // 2 Bytes
2
const int __memx *q; int q_len = sizeof(q); // 3 Bytes
Für 16-Bit x86 bist du zu jung?

: Bearbeitet durch User
von Gerald K. (geku)


Lesenswert?

Rolf M. schrieb:
> Dann solltest du da eigentlich auch eine bekommen.

Danke, bekomme ich.

Beispiel:
- erstes printf() mit %x
- zweites printf() mit %p

Beim Raspberry Pi haben int und Zeiger die gleiche Größe.

1
static *&a 0x2102c=4711
2
pi@test:~/test $ gcc -Wall t1.c
3
t1.c: In function ‘test’:
4
t1.c:13:22: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat=]
5
  printf("static *&a %x=%d\r\n",&a,a);
6
                                 ~^                ~~
7
                                 %ls
8
9
10
pi@test:~/test $ ./a.out
11
static *&a 2102c=4711
12
static *&a 0x2102c=4711
13
pi@test:~/test $

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

P. S. schrieb:
> Viele Coding-Standards schreiben schließlich auch die explizite
> Initialisierung von static Variablen vor.

Da würde ich allerdings die Kompetenz der Ersteller dieser Standards 
anzweifeln. Wie ja oben schon geschrieben wurde, bringt eine explizite 
Initialisierung im besten Falle rein gar nichts *), im schlechteren 
Falle sogar eine Pessimierung (mehr Code-Verbrauch).

*) Wenn die Initialisierung des .bss mit 0 kaputt ist, dann hat man 
sowieso ganz andere Probleme. Allerdings hatte ich den Fall in der 
Praxis tatsächlich noch nicht, den Fall, dass .data nicht sauber mit 
Werten vorgeladen worden ist, hatte ich dagegen schon mal (Diskrepanz 
zwischen Startup-Code und Linkersript in einer MCU-Implementierung).

Mit Coding-Standards, die eine zwingende Initialisierung von 
auto-Variablen fordern, gehe ich gerade noch so mit, wenngleich (wie 
oben schon geschrieben) ich auch diese aufgrund meiner Erfahrung für 
teils kontraproduktiv halte, da sie Warnungen kaschieren kann, die einen 
auf Fehler im Code hinweisen. Die entsprechenden Warnungen beherrschen 
die Compiler mittlerweile nämlich genauso gut (manchmal geringfügig zu 
aggressiv), wie sie zuverlässig ein
1
   if (foo = 42) {
2
      ...
3
   }

warnen können.

: Bearbeitet durch Moderator
von Oliver S. (oliverso)


Lesenswert?

Jörg W. schrieb:
> P. S. schrieb:
>> Viele Coding-Standards schreiben schließlich auch die explizite
>> Initialisierung von static Variablen vor.
>
> Da würde ich allerdings die Kompetenz der Ersteller dieser Standards
> anzweifeln. Wie ja oben schon geschrieben wurde, bringt eine explizite
> Initialisierung im besten Falle rein gar nichts *), im schlechteren
> Falle sogar eine Pessimierung (mehr Code-Verbrauch).

Es gibt/gab halt anscheinend doch Compiler bzw. linker-Startscripsts, 
die vom C-Standard noch nie was gehört haben. Und einmal eingeführt, 
halten sich solche Regeln dann unendlich lange.

Oliver

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> Und einmal eingeführt, halten sich solche Regeln dann unendlich lange.

Ja, das ist wie mit
1
  if (42 == foo) {
2
     ...

Dabei braucht man das seit 20 Jahren nicht mehr in dieser Reihenfolge, 
und für den Fall
1
  if (foo = bar) {

würde diese Regel sowieso nicht helfen (die Warnung des Compilers 
dagegen schon).

: Bearbeitet durch Moderator
von Dirk B. (dirkb2)


Lesenswert?

Gerald K. schrieb:
> Beim Raspberry Pi haben int und Zeiger die gleiche Größe.

Das verschleiert ja nur den Fehler.

von Dirk B. (dirkb2)


Lesenswert?

P. S. schrieb:
> Viele Coding-Standards schreiben schließlich auch die explizite
> Initialisierung von static Variablen vor.

Viele Coding-Standards dienen nur dazu, den Code von Leuten Prüfen zu 
lassen, die die Sprache nicht kennen.
Bei C muss man nicht viel wissen, aber das ist dann aber auch wichtig.

von A. S. (achs)


Lesenswert?

Dirk B. schrieb:
> Viele Coding-Standards dienen nur dazu, den Code von Leuten Prüfen zu
> lassen, die die Sprache nicht kennen.

Vor allem erhöht die unnötige Initialisierung die Anzahl der 
(erfolgreichen) Tests und damit die Qualität. Wenn dann noch etwas 
schief geht (z.B. weil jemand das static vergessen hat und der Compiler 
nicht warnen konnte), lag es nicht an mangelnder Sorgfalt.

von Sebastian (Gast)


Lesenswert?

Jörg W. schrieb:
> Allerdings hatte ich den Fall in der Praxis tatsächlich noch nicht,

AVR Bootloader?

LG, Sebastian

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Sebastian schrieb:
>> Allerdings hatte ich den Fall in der Praxis tatsächlich noch nicht,
>
> AVR Bootloader?

Auch da spricht nichts dagegen, dass man .bss ausnullt. Ist ja allemal 
noch einfacher, als .data zu kopieren.

Am Ende ist ein Bootloader aber ohnehin ein "ganz normales Programm", 
das lediglich auf eine höhere Adresse gelinkt wird und sein Ende durch 
einen Sprung auf Adresse 0 findet. Wenn man den Bootloader in C 
schreibt, gibt es folglich erstmal keinen Grund, auf den regulären 
C-Startup-Code zu verzichten.

Aber wie geschrieben, den Fall, dass das Kopieren von .data vermurkst 
worden ist, hatten wir tatsächlich schon.

von dfIas (Gast)


Angehängte Dateien:

Lesenswert?

Snapshots vom feinweichen Studio beiliegend.
Die Meldung vom as-you-type analyzer (die Glühbirne "Helferlein" ganz 
links) gibt's dann und wann auch vom Compiler selbst. Nicht immer, aber 
immer öfter.
Und laut Feinweich gibt es sowohl einen ISO C++14 Standard, als auch 
einen ISO C++17 Standard. So nennen die es halt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

dfIas schrieb:
> Die Meldung vom as-you-type analyzer (die Glühbirne "Helferlein" ganz
> links) gibt's dann und wann auch vom Compiler selbst.

Compiler sind natürlich frei darin, was sie alles warnen, aber diese 
Warnung hat keinen Sinn – egal, ob sie nun von der IDE oder dem Compiler 
kommt.

von A. S. (achs)


Lesenswert?

Jörg W. schrieb:
> aber diese Warnung hat keinen Sinn – egal, ob sie nun von der IDE oder
> dem Compiler kommt.

Vermutlich ging es um was ganz anderes bei

dfIas schrieb:
> Und laut Feinweich gibt es sowohl einen ISO C++14 Standard, als auch
> einen ISO C++17 Standard.

Er hat den Post oben missverstanden:

Dennis S. schrieb:
> Es gibt keinen C-Standard der in irgendeiner Weise C++17 genannt wird.

Weil er den OP nicht ganz gelesen hat.

Thomas Z. schrieb:
> Bedeutung von static in C

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Das kann schon sein, es gibt ein C++17 aber kein C17. Das ändert aber 
nichts daran, dass eine Warnung über eine "nicht initialisierte" 
static-Variable weder in C noch in C++ sinnvoll ist. Daher hatte ich mir 
diesen Aspekt heraus genommen.

von Rolf M. (rmagnus)


Lesenswert?

Jörg W. schrieb:
> Das kann schon sein, es gibt ein C++17 aber kein C17.

Nur ist C++17 eben kein C-Standard, und ich denke, das ist es, was damit 
gemeint war:

Dennis S. schrieb:
> Es gibt keinen C-Standard der in irgendeiner Weise C++17 genannt wird.

Der aktuelle C-Standard ist übrigens sowohl als C17, als auch als C18 
bekannt. Es gibt also ein C17.
https://en.wikipedia.org/wiki/C17_(C_standard_revision)

von chris_ (Gast)


Lesenswert?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite
>16.06.2021 07:16

>Klaus W. schrieb:
>> (Trotzdem empfehle ich es, explizit zu schreiben)

>Mit welcher Begründung?

Ich empfehle hier, sich an die MISRA-Regeln zu halten und explizit zu 
initialisieren:

https://rules.sonarsource.com/c/RSPEC-836

Meiner Meinung nach sollte Code immer einfach und eindeutig sein und 
dafür sind die MISRA-Regeln sehr gut geeignet.

von Yalu X. (yalu) (Moderator)


Lesenswert?

chris_ schrieb:
> Ich empfehle hier, sich an die MISRA-Regeln zu halten und explizit zu
> initialisieren:
>
> https://rules.sonarsource.com/c/RSPEC-836
>
> Meiner Meinung nach sollte Code immer einfach und eindeutig sein und
> dafür sind die MISRA-Regeln sehr gut geeignet.

Einfacher und dennoch eindeutig ist das Weglassen der expliziten
Initialisierung bei statischen Variablen.

Die verlinkte MISRA-Regel bezieht sich auf automatische Variablen. Da
steht nämlich "to avoid unexpected behaviors due to garbage values". Man
schaue sich auch die Beispiele an.

Für statische Variablen ist die Regel sowieso erfüllt, da diese
automatisch immer initialisiert sind.

: Bearbeitet durch Moderator
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

chris_ schrieb:

> Meiner Meinung nach sollte Code immer einfach und eindeutig sein und
> dafür sind die MISRA-Regeln sehr gut geeignet.

MISRA ist gut, um Manager zu beruhigen. Da ist auch viel Sinnvolles 
dabei, aber auch manches, was mit heutigen Compilern eigentlich nicht 
mehr sinnvoll ist, sich aber trotzdem hartnäckig hält. Beispiele habe 
ich genannt.

von chris_ (Gast)


Lesenswert?

>MISRA ist gut, um Manager zu beruhigen. Da ist auch viel Sinnvolles
>dabei, aber auch manches,

Du hast schon recht. Ich befolge auch nicht alle sklavisch. Wenn's aber 
um die Frage geht, ob der Compiler die static Variable sicher auf 0 
initialisiert oder nicht, will ich da gar nicht nachschauen, sondern 
schreibe es einfach hin. Dann müssen sich andere, die den Code lesen, da 
auch keine Gedanken machen.

von P. S. (namnyef)


Lesenswert?

MISRA fordert NICHT die explizite Initialisierung von static Variablen, 
sondern nur von Variablen mit "automatic storage duration".

Im "Rationale" der entsprechenden Regel heißt es auch:
According to the Standard, objects with static storage duration are 
automatically initialized to zero unless initialized explicitly. Objects 
with automatic storage duration are not automatically initialized and 
can therefore have indeterminate values.

von A. S. (achs)


Lesenswert?

Jörg W. schrieb:
> MISRA ist gut, um Manager zu beruhigen.

MISRA ist auch für Entwickler(Teams) gut. Keine Forderung ist wirklich 
unsinnig und bietet gerade für Anfänger oder leidenschaftslose 
Programmierer eine gute Möglichkeit der Reflektion.

Würde MISRA wirklich fordern, Variablen explizit zu initialisieren, dann 
gäbe es eine gut begründete Abweichung. Dann man hat eine verbindliche 
Stelle, um "selbsternannte Experten" davon abzubringen.

Für kleine, engagierte Teams mit 10+ Jahren Erfahrung klingen natürlich 
manche Punkte wie Gängelung. Da ist das aber auch in wenigen Stunden 
abgehakt.

von Rolf M. (rmagnus)


Lesenswert?

chris_ schrieb:
> Ich empfehle hier, sich an die MISRA-Regeln zu halten und explizit zu
> initialisieren:
>
> https://rules.sonarsource.com/c/RSPEC-836
>
> Meiner Meinung nach sollte Code immer einfach und eindeutig sein und
> dafür sind die MISRA-Regeln sehr gut geeignet.

Manchen Code muss man umständlicher schreiben, weil man nach MISRA 
bestimmte Sprachfeatures nicht nutzen darf.

P. S. schrieb:
> MISRA fordert NICHT die explizite Initialisierung von static Variablen,
> sondern nur von Variablen mit "automatic storage duration".
>
> Im "Rationale" der entsprechenden Regel heißt es auch:
> According to the Standard, objects with static storage duration are
> automatically initialized to zero unless initialized explicitly. Objects
> with automatic storage duration are not automatically initialized and
> can therefore have indeterminate values.

Wobei ich selbst die erzwungene Initialisierung von automatischen 
Variablen in Frage stellen würde. Meistens ist es natürlich sinnvoll, 
aber es gibt Fälle, in denen man an der Stelle der Definition einfach 
noch keinen sinnvollen Initialisierungswert hat. An der Stelle würde ich 
die Variable dort auch nicht initialisieren wollen mit irgendwas, nur 
damit sie halt einen Wert hat. Das Problem: Wenn ich später dann 
vergesse, der Variablen dann einen sinnvollen Wert zuzuweisen, sagt der 
Compiler nichts. Wäre sie nicht initialisiert gewesen, hätte ich eine 
Warnung bekommen.

A. S. schrieb:
> Jörg W. schrieb:
>> MISRA ist gut, um Manager zu beruhigen.
>
> MISRA ist auch für Entwickler(Teams) gut. Keine Forderung ist wirklich
> unsinnig und bietet gerade für Anfänger oder leidenschaftslose
> Programmierer eine gute Möglichkeit der Reflektion.

Das ist gerade mein Problem mit MISRA: Schlechte Programmierer werden 
mit MISRA nicht automatisch zu guten Programmierern. Und gute 
Programmierer wissen, wo sie auch von dem, was MISRA vorgibt, problemlos 
abweichen können. Es gibt fast kein Sprachfeature, das niemals nützlich 
ist.
Sinnvoller, als irgendein Dokument zu haben, dass einem solche 
Einschränkungen auferlegt, wäre, die Programmierer im Umgang mit ihrem 
Werkzeug ordentlich zu schulen, mit Prüfung.

: Bearbeitet durch User
von A. S. (achs)


Lesenswert?

Rolf M. schrieb:
> Sinnvoller, als irgendein Dokument zu haben, dass einem solche
> Einschränkungen auferlegt, wäre, die Programmierer im Umgang mit ihrem
> Werkzeug ordentlich zu schulen, mit Prüfung.

Aber genau das macht und fordert MISRA. Zwar jetzt kein Test zur 
Kenntnis der Regeln, aber immerhin eine Prüfung der Einhaltung. Hast Du 
einen MISRA-Standard mal gelesen?

von Rolf M. (rmagnus)


Lesenswert?

A. S. schrieb:
> Aber genau das macht und fordert MISRA. Zwar jetzt kein Test zur
> Kenntnis der Regeln, aber immerhin eine Prüfung der Einhaltung.

Genau das ist es aber, was ich nicht meine. Leute, die ihr Werkzeug 
beherrschen, brauchen diese Regeln, um dessen Benutzung einzuschränken, 
nicht. Da muss man hin, und nicht dahin, dass stumpf irgendwelche Regeln 
befolgt werden und man dann glaubt, nichts mehr falsch machen zu können.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rolf M. schrieb:
> Wobei ich selbst die erzwungene Initialisierung von automatischen
> Variablen in Frage stellen würde.

+1

Ich habe halt schon Fälle gesehen, wo mir die Warnung des Compilers "foo 
may be used uninitialized" sehr viel wichtiger war, denn sie hat mich 
auf einen Fehler in meinem Code hingewiesen. (Da sollte im Programmfluss 
ein Wert zugewiesen werden, aber die Stelle wurde aufgrund eines Bugs 
nicht immer erreicht.) Ein lemminghaftes "= 0", wie es MISRA leider 
fordert, hätte mir genau diesen Fehler kaschiert und mich hinterher 
tagelang suchen lassen.

Wenn ich nun aber die MISRA-Ausnahme erst explizit in einem 10seitigen 
Antrag begründen muss, warum ich da kein "= 0" geschrieben habe, mal 
ehrlich, dann bin ich als Programmierer faul und schreibe halt 
lemminghaft das "= 0" immer hin. Und suche hinterher den Bug, den mir 
sonst der Compiler angewarnt hätte.

Sorry, ist off-topic, es ging ja um statische Objekte.

von A. S. (achs)


Lesenswert?

Jörg W. schrieb:
> Wenn ich nun aber die MISRA-Ausnahme erst explizit in einem 10seitigen
> Antrag begründen muss, warum ich da kein "= 0" geschrieben habe, mal
> ehrlich, dann bin ich als Programmierer faul und schreibe halt
> lemminghaft das "= 0" immer hin. Und suche hinterher den Bug, den mir
> sonst der Compiler angewarnt hätte.

Genau das sollst Du bei Misra nicht! Du stellst einmal fest, dass Dein 
Compiler/Lint Dich zuverlässig warnt und fertig.

Es geht doch gerade darum, einen gemeinsamen Standard zu finden. Sonst 
gibt es die einen, die auto-Variablen grundweg initialisieren, und 
zwingen quasi die anderen diese "exotischen" Warnungen abzuschalten.

Schau doch mal alleine hier, wie viele mit Wall schon meinen, sie hätten 
alle Warnungen eingeschaltet. Und MISRA richtet sich ja auch an typische 
Programmierer mit 2-3 Jahren Erfahrung. Was ein Betrieb daraus macht, 
hängt von den erfahrenen Profis der Firma ab.

Betrachte MISRA einfach als große Checkliste, in der die 100 wichtigsten 
Punkte der Sprache C einmal angesprochen und entschieden werden. Es ist 
ausdrücklich NICHT gedacht, den Standard ungefragt zu übernehmen.

von mh (Gast)


Lesenswert?

A. S. schrieb:
> Betrachte MISRA einfach als große Checkliste, in der die 100 wichtigsten
> Punkte der Sprache C einmal angesprochen und entschieden werden. Es ist
> ausdrücklich NICHT gedacht, den Standard ungefragt zu übernehmen.

Rolf M. schrieb:
> A. S. schrieb:
>> Aber genau das macht und fordert MISRA. Zwar jetzt kein Test zur
>> Kenntnis der Regeln, aber immerhin eine Prüfung der Einhaltung.
>
> Genau das ist es aber, was ich nicht meine. Leute, die ihr Werkzeug
> beherrschen, brauchen diese Regeln, um dessen Benutzung einzuschränken,
> nicht. Da muss man hin, und nicht dahin, dass stumpf irgendwelche Regeln
> befolgt werden und man dann glaubt, nichts mehr falsch machen zu können.

Und Leute, die ihr Werkzeug nicht beherrschen, sollten die Zeit nicht 
mit dem Lesen dieser Regeln verschwenden und statt dessen den Umgang mit 
dem Werkzeug lernen.
Und nein, die Regeln helfen nicht beim Lernen. Das sieht man schön an 
der oben verlinkten Regel. Es gibt keine wirkliche Erklärung
- was das Problem ist,
- warum ein =0 das Problem beseitigt,
- was man macht, wenn =0 nicht genutzt werden kann und
das Beispiel ist, wie üblich, schlecht gewählt.

von A. S. (achs)


Lesenswert?

mh schrieb:
> Und nein, die Regeln helfen nicht beim Lernen. Das sieht man schön an
> der oben verlinkten Regel. Es gibt keine wirkliche Erklärung
> - was das Problem ist,
> - warum ein =0 das Problem beseitigt,
> - was man macht, wenn =0 nicht genutzt werden kann und
> das Beispiel ist, wie üblich, schlecht gewählt.

Eine Vorschrift, wie Du sie beschreibst, kenne ich nicht. chris_ hat das 
gefordert, nicht sein verlinkter Artikel (der auch nicht MISRA ist).

In Misra 2012 heißt die Regel z.B. (9.1):
> The value of an object with automatic storage duration
> shall not be read before it has been set

Ich würde es eher als selbstverständlich ansehen, denn als unsinnig.

Es gibt dazu eine Seite Erklärung und Beispiele. Das Beispiel ist nicht 
trivial:
1
void f(bool_t b, uint16_t *p)
2
{
3
   if(b) *p=3U;
4
}
5
6
void g(void)
7
{
8
   uint16_t u;
9
   f(false, &u);
10
   if(u==3U) {..} // Non-complient ... 
11
}

Misra fordert weder, dass u sofort initialisiert wird, noch dass es vor 
dem Aufruf von f passiert. Sondern nur, dass es vor der Abfrage 
geschehen ist.

Was bitte soll daran falsch sein?
Wo bitte sollte man sowas regelmäßig durchgehen lassen?

Sie gehen sogar extra noch daraus ein, dass man auch nicht mit goto um 
die Initialisierung herumspringen sollte.

(Und natürlich kann man auch goto nach MISRA 2012 so oft verwenden wie 
man will, wenn man sich darauf einigt, es ist nur "advisory".)

Ich glaube fast, manche haben sich ihre Meinung zu MISRA gebildet, 
obwohl sie nur Erfahrung aus zweiter Hand haben.

Wer (auch als Experte) das Werk liest, wird feststellen, dass es 
komprimiert UB, ID und Pitfalls von vielen Seiten beleuchtet.

Und ja, natürlich gibt es viele Dinge, die ich als lästig empfinde. Bei 
jedem umstrittenen Punkt gab es aber auch (langjährige) Kollegen, denen 
die Pitfalls gar nicht klar waren.

P.S.: die Regel ist eine von 2 unter dem Kapitel "Overlapping storage", 
also wo Speicher mehrfach genutzt wird. Die andere ist, keine union zu 
verwenden, ist aber nur "advisory" und daher: Wer's mag, machts.

Und auch da ist erklärt: "Wenn man es verwendet, denkt an Padding, 
Alignment, Endianess und Bit-order." Das ist doch konstruktiv.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

A. S. schrieb:
> Misra fordert weder, dass u sofort initialisiert wird, noch dass es vor
> dem Aufruf von f passiert. Sondern nur, dass es vor der Abfrage
> geschehen ist.
>
> Was bitte soll daran falsch sein?

Daran ist nichts falsch. Genau so würde ich es auch sehen. Ich war davon 
ausgegangen, dass das stimmt:

P. S. schrieb:
> MISRA fordert NICHT die explizite Initialisierung von static Variablen,
> sondern nur von Variablen mit "automatic storage duration".


> Sie gehen sogar extra noch daraus ein, dass man auch nicht mit goto um
> die Initialisierung herumspringen sollte.
>
> (Und natürlich kann man auch goto nach MISRA 2012 so oft verwenden wie
> man will, wenn man sich darauf einigt, es ist nur "advisory".)

Soweit ich sehen kann, galt das aber nicht immer. Vor 2012 war es 
komplett verboten.

> Ich glaube fast, manche haben sich ihre Meinung zu MISRA gebildet,
> obwohl sie nur Erfahrung aus zweiter Hand haben.

Ich muss zugeben, dass du da zumindest im Bezug auf mich Recht hast.

> P.S.: die Regel ist eine von 2 unter dem Kapitel "Overlapping storage",
> also wo Speicher mehrfach genutzt wird. Die andere ist, keine union zu
> verwenden, ist aber nur "advisory" und daher: Wer's mag, machts.
>
> Und auch da ist erklärt: "Wenn man es verwendet, denkt an Padding,
> Alignment, Endianess und Bit-order." Das ist doch konstruktiv.

Wenn es tatsächlich so einfach ist, ja.

von P. S. (namnyef)


Lesenswert?

Jörg W. schrieb:
> Ein lemminghaftes "= 0", wie es MISRA leider
> fordert

Auch das ist falsch. MISRA fordert lediglich, dass ein Wert nicht 
gelesen werden darf bevor er gesetzt wurde.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

P. S. schrieb:
> MISRA fordert lediglich, dass ein Wert nicht
> gelesen werden darf bevor er gesetzt wurde.

Das wiederum ist nun eine völlig selbstverständliche Foderung.

Zumindest haben einige Styleguides (wie Barr) jedoch eher solche 
lemminghaften Vorschriften kreiert, und sie berufen sich dabei 
zuallererst auf MISRA.

von P. S. (namnyef)


Lesenswert?

Jörg W. schrieb:
> Das wiederum ist nun eine völlig selbstverständliche Foderung.
Welcome to the real world.

von A. S. (achs)


Lesenswert?

Jörg W. schrieb:
> Das wiederum ist nun eine völlig selbstverständliche Foderung.

Ziele von MISRA sind auch weniger die Forderungen, ... als deren 
Einhaltung. Also Lint & Co so scharf zu schalten, dass Verletzungen der 
vereinbarten ("selbstverständlichen") Regeln erkannt werden.

Misra verwenden heißt:
 * ein fester Rahmen für die Vereinbarungen
 * ein gemeinsames Verständnis der Regeln
 * eine Testsuite zur Prüfung, ob die vereinbarten automatisch prüfbaren 
Regeln auch sicher erkannt und sicher nicht falsch erkannt werden
 * Verfahren, um die nicht automatisch prüfbaren Regeln zu prüfen.

Ist zwar ein wenig Aufwand, aber geballte Erfahrung auf wenigen Seiten 
für fast kostenlos.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.