Forum: Compiler & IDEs Unterschiede des Variablen-Erstellens


von Senmeis (Gast)


Lesenswert?

Hallo,

gibt es Unterschiede (Reihenfolge des Kopierens in RAM usw.) der 
Variablen, wenn sie sich in der main-Datei oder in anderen C-Dateien 
befinden? Wenn man eine Variable bei Runtime erstellen möchte, muß sie 
in der main-Datei sein?

Also z.B.
1
if (Bedinungen)
2
  int var = 100;
3
else
4
  int var = 200;
Gruss

von Uhu U. (uhu)


Lesenswert?

Zunächst müssen wir uns über die Sprache einigen, in der das formuliert 
ist:

Wenn es C sein soll, dann quittiert es der Compiler mit einem Aufschrei 
- die Frage der Reihenfolge erübrigt sich...

Wenn es C++ ist, macht der Compiler implizit folgendes draus:

   if (Bedinungen) {
      int var = 100;
   } else {
      int var = 200;
   }

Damit dürfte klar sein, daß sich auch hier die Frage der Reihenfolge 
nicht stellt...

von Karl H. (kbuchegg)


Lesenswert?

Senmeis wrote:
> Hallo,
>
> gibt es Unterschiede (Reihenfolge des Kopierens in RAM usw.) der
> Variablen, wenn sie sich in der main-Datei oder in anderen C-Dateien
> befinden?

Nein.
Denn letztendlich läuft am Computer ja nur 1 Programm ab.
Egal aus wievielen Bestandteilen diese Programm zusammengesetzt
wurde.

> Wenn man eine Variable bei Runtime erstellen möchte, muß sie
> in der main-Datei sein?
>
> Also z.B.
>
1
if (Bedinungen)
2
>   int var = 100;
3
> else
4
>   int var = 200;
5
>

Das geht zwar, bringt dich aber nicht weiter.
Du solltest den Erwerb eines Lehrbuches über C ernsthaft
in Erwägung ziehen.

Es gibt:
globale Variablen:
   Diese sind in allen Kompiliereinheiten (den *.c Files) sichtbar.
   Sie werden erzeugt, wenn das Programm hochfährt, also noch bevor
   die main() Funktion die Kontrolle erhält

modullokale Variablen:
   Sind im Grunde globale Variablen, nur ist ihr Sichtbarkeits-
   bereich eingeschränkt auf das Modul (dem einen *.c) File, in
   dem sie definiert sind.
   Sie werden, wie globale Variablen, beim Hochfahren erzeugt,
   noch ehe main() die Kontrolle kriegt

funktionslokale Variablen:
   Also Variablen die innerhalb einer Funktion angelegt werden.
   Sie werden erzeugt, wenn die Funktion betreten wird und werden
   zerstört, wenn die Funktion verlassen wird.
   Seit einiger Zeit wurden diese Variablen an C++ angeglichen
   und ihre Lebensdauer auf den Block beschränkt, in dem sie
   definiert wurden.

funktionslokale static Variablen:
   Sind ein bischen wie globale Variablen, nur dass sie erst erzeugt
   werden, wenn die Funktion das erste mal betreten wird. Von dem
   Zeitpunkt an existieren sie aber, bis zum Beenden des Programms.
   Ausserhalb der Funktion in der sie definiert wurden, sind sie
   nicht sichtbar.

Bsp:
1
int Global;     // eine globale Variable, jeder der will kann von
2
                // einem anderen *.c File auf diese Variable zugreifen
3
4
static int ModulGlobal;   // eine modulglobale Variable. Alle Funktionen
5
                          // in diesem *.c File können darauf zugreifen
6
                          // Aber ausserhalb dieses *.c Files ist diese
7
                          // Variable nicht sichtbar
8
9
void foo()
10
{
11
  int j;         // diese Variable existiert nur in dieser Funktion
12
                 // Ausserhalb dieser Funktion, ist diese Variable
13
                 // nicht sichtbar. Bei Beendingung der Funktion foo
14
                 // wird die Variable zerstört
15
16
  static int k;  // diese Variable existiert ebenfalls nur in dieser
17
                 // Funktion. Aber anders als j, überlebt diese
18
                 // Variable das Funktionsende und steht beim nächsten
19
                 // Aufruf von foo in alter Frische (und mit demselben
20
                 // Inhalt) wieder zur Verfügung
21
22
  if (irgendwas) {      // Ein Block beginnt
23
    int m;              // diese Variable existiert nur in diesem Block
24
    m = 5;
25
    int n;              // diese Variable existiert ebenfalls nur
26
                        // in diesem Block
27
28
  }                     // der Block endet hier. Als Konsequenz werden
29
                        // m und n daher zerstört, da ihre Lebensdauer
30
                        // auf diesen Block beschränkt ist. j hingegen
31
                        // wurde ausserhalb des Blocks definiert und
32
                        // existiert daher weiter
33
34
}                       // hier endet die Funktion. Alle Variablen, die
35
                        // funktionslokal, aber nicht static definiert
36
                        // wurden, werden zerstört. Konkret ist das
37
                        // die Variable j, aber *nicht* k

von yalu (Gast)


Lesenswert?

> funktionslokale static Variablen:
>    Sind ein bischen wie globale Variablen, nur dass sie erst erzeugt
>    werden, wenn die Funktion das erste mal betreten wird.

Ist das so? Ich habe immer gedacht, dass globale, modullokale und
funktionslokale static Variablen speicher- und lebensdauertechnisch
gleich sind und sich nur im Sichbarkeitsbereich unterscheiden, d. h.
auch eine funktionslokale static Variable braucht von Anfang an
Speicher und wird auch bereits vor dem main() initialisiert.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Das kann so sein, muss aber nicht. Die funktionslokale statische 
Variable kann bei bestimmten Architekturen mitten im Codesegment 
angelegt werden. Beim Compilieren werden "einfach Data-Statements 
eingefügt" und deren Adressen zu lokalen Variablen verwurschtelt. Bei µC 
spielt das weniger eine Rolle, weil der Code oft im Flash liegt.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Würden funktionslokale statische Variablen erst dann erzeugt, "wenn die 
Funktion das erste mal betreten wird", müsste dafür ein dynamischer 
Speicherverwaltungsmechanismus verwendet werden, weil so ja Speicher 
erst zur Laufzeit des Programmes allokiert würde.

Der Unterschied zwischen static auf Modulebene und static innerhalb 
einer Funktion liegt nur in der "Sichtbarkeit", nicht aber im Zeitpunkt 
der Speicherreservierung und auch nicht der Initialisierung.
Da hat wohl yalu recht.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Rufus war schneller mit seiner Antwort bzw. ich war zu lahm mit dem 
Bearbeiten!

Richtig, auch das Einstreuen in den Code ist sogesehen ein "braucht von 
Anfang an Speicher und wird auch bereits vor dem main() initialisiert."

"Vor dem main()" kann dann ggf. heissen, dass der Compiler die passenden 
Bytes in den dafür reservierten Codebereich einstreut.

Ich habe da was mit Speicherreservierung verwechselt und wollte 
eigentlich nur darauf hinweisen, dass die funktionslokale statische 
Variable nicht im DATA oder BSS Speicherbereich liegen muss.

von Uhu U. (uhu)


Lesenswert?

Einen Unterschied gibt es:
1
void f() {
2
   static int local_static = k();
3
   ...
4
}

Dann wird die Initialisierung erst beim ersten Betreten von f() 
ausgeführt.
Der Speicher für local_static wird natürlich bereits vom Linker 
reserviert.

von Karl H. (kbuchegg)


Lesenswert?

Rufus t. Firefly wrote:
> Würden funktionslokale statische Variablen erst dann erzeugt, "wenn die
> Funktion das erste mal betreten wird", müsste dafür ein dynamischer
> Speicherverwaltungsmechanismus verwendet werden, weil so ja Speicher
> erst zur Laufzeit des Programmes allokiert würde.
>
> Der Unterschied zwischen static auf Modulebene und static innerhalb
> einer Funktion liegt nur in der "Sichtbarkeit", nicht aber im Zeitpunkt
> der Speicherreservierung und auch nicht der Initialisierung.
> Da hat wohl yalu recht.

Das mag schon so sein, dass der Speicher im globalen
Pool reserviert wird. Aber initialisiert wird die
Variable erst beim ersten Betreten. Und erst dann
existiert die Variable.

Von der programmtechnischen Sicht macht es keinen Unterschied
ob die Speicherreservierung schon vor dem ersten Funktionsaufruf
stattgefunden hat oder nicht. Das ist Sache des Runtimesystems.
Für mich als Programmierer ist entscheidend, wann ich zum
ersten mal auf die Variable zugreifen kann und welchen Wert
sie dann hat. Und das wird beim ersten Funktionsaufruf
festgelegt.

von Karl H. (kbuchegg)


Lesenswert?

Hmm

Im Prinzip könnte ein Compiler auf die Idee kommen, die
Allokierung einer lokalen static Variable auf den tatsächlichen
Funktionsaufruf zu verschieben. Der Compiler legt global einen
Pointer dafür an und macht die Allokierung dann zur Laufzeit.
Natürlich müsste er dann alle Verwendungen der Variable auf
den Pointer umstellen, aber da ich als Programmierer den
Unterschied nicht feststellen kann, wäre das m.W. standardkonform

wie implementiert der gcc eigentlich Folgendes:
1
void foo( size_t k )
2
{
3
  static int bar[k];
4
5
  bar[0] = 5;
6
}

Wenn das geht (keine Ahnung ob das zulässig ist), dann hat
der Compiler gar keine andere Chance als die Allokierung
bis zum ersten Funktionsaufruf zu verschieben. Im Grunde
muss er das umpfriemeln zu (semantisch nicht exakt 100%
äquivalent, weil der Scope nicht stimmt)
1
static int* bar = NULL;
2
3
void foo( size_t k )
4
{
5
  if( bar == NULL )
6
    bar = calloc( k * sizeof (*bar) );
7
8
  bar[0] = 5;
9
}

Ich wüsste nicht, wie der Compiler das sonst machen sollte.

von Uhu U. (uhu)


Lesenswert?

1
void foo( size_t k )
2
{
3
  static int bar[k];
4
5
  bar[0] = 5;
6
}

Gültiges C / C++ ist das nicht.
C99 definiert meines Wissens dynamische Arrays - dort müßte es gehen.

Tipp: Schalte beim ersten Betreten eines Blocks mit einer nichtkonstant 
initialisierten statischen Variablen in den Assembler-Debugmodus, dann 
kannst du sehen, was da veranstaltet wird.

VC++ beispielsweise reserviert eine zusätzliche, unsichtbare 
bool-Variable als Kennzeichen dafür, ob die statische Variable 
initialisiert ist.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

1
void foo( size_t k )
2
{
3
  static int bar[k];
4
  ...

schmeisst beim GCC (gnu99 Einstellung) den error: "storage size of bar 
isn't constant"

von Mathematiker (Gast)


Lesenswert?

> Im Prinzip könnte ein Compiler auf die Idee kommen, die
> Allokierung einer lokalen static Variable auf den tatsächlichen
> Funktionsaufruf zu verschieben.

In C++ ist es vom Standard vorgeschrieben, dass lokale static-Variablen 
beim ersten Aufruf initialisiert werden und nicht früher. Nur deswegen 
macht zum Beispiel folgendes Singleton-Pattern Sinn:
1
class X {
2
public:
3
  X& the_one_and_only() {
4
    static X x;
5
    return x;
6
  }
7
8
private:
9
  X();
10
};
Ohne die Garantie, dass das Objekt x erst zum spätmöglichsten Zeitpunkt 
initialisiert wird, könnte man sich im Konstruktor von X nicht darauf 
verlassen, dass z.B. std::cout existiert.
Der andere Punkt ist, dass die Initialisierung von X sehr aufwändig sein 
kann, und deswegen besser nicht vor main() erledigt wird (denn dann kann 
man noch keinen Ladebalken anzeigen).

von Mathematiker (Gast)


Lesenswert?

Nachtrag: Der Allozierungs-Zeitpunkt des Speicher-Blocks der Größe 
sizeof(X) ist allerdings nicht festgelegt, soweit ich weiß.

von Falk (Gast)


Lesenswert?

@  Karl heinz Buchegger (kbuchegg)

>Das mag schon so sein, dass der Speicher im globalen
>Pool reserviert wird. Aber initialisiert wird die
>Variable erst beim ersten Betreten. Und erst dann
>existiert die Variable.

Bist du da sicher? Das wäre doch ein ziemlicher Aufwand, wenn der 
Compiler Code generieren müsste, welcher bei JEDEM Aufruf der Funktion 
prüft, ob es der erste Aufruf ist und wenn ja die statischen Variablen 
initialisiert. Ist es nicht tausendmal einfacher, besser und vom 
Ergebniss identisch, wenn lokale statische Variablen einfach wie alle 
anderen initialisierten globalen Variablen vor dem Aufruf von main() 
reserviert und initialisiert wird? Ist doch am Ende nur nen Blockkopie 
aus dem FLASH.

MFG
Falk

von Karl H. (kbuchegg)


Lesenswert?

Falk wrote:
> @  Karl heinz Buchegger (kbuchegg)
>
>>Das mag schon so sein, dass der Speicher im globalen
>>Pool reserviert wird. Aber initialisiert wird die
>>Variable erst beim ersten Betreten. Und erst dann
>>existiert die Variable.
>
> Bist du da sicher?

Ja. Da bin ich mir sicher.

> Das wäre doch ein ziemlicher Aufwand, wenn der
> Compiler Code generieren müsste, welcher bei JEDEM Aufruf der Funktion
> prüft, ob es der erste Aufruf ist und wenn ja die statischen Variablen
> initialisiert. Ist es nicht tausendmal einfacher, besser und vom
> Ergebniss identisch,

Der springende Punkt ist:
Es gibt Fälle, bei denen es eben nicht identisch ist. Die
sind noch nicht mal schwer zu konstruieren.
1
void foo( int i )
2
{
3
  static int k = i;
4
}

Wenn der Compiler beweisen kann, dass es keinen Unterschied
macht, dann kann er das als Optimierung natürlich so machen,
dass die Initialisierung beim Programmstart gemacht wird
(wenn die Initialisierung zb. eine Konstante ist). Aber konzeptionell
findet die Initialisierung erst beim Funktionsaufruf statt, weil
die Variable offiziell davor nicht existiert.

Aber natürlich gilt, die 'oberste Direktive der Optimierung',
die 'as-if' Regel: Der Compiler darf alles machen und umstellen,
solange das Programm die Optimierung nicht feststellen kann und
die Programmlogik gleich bleibt.

von Falk (Gast)


Lesenswert?

@  Karl heinz Buchegger (kbuchegg)

>Der springende Punkt ist:
>Es gibt Fälle, bei denen es eben nicht identisch ist. Die
>sind noch nicht mal schwer zu konstruieren.

>void foo( int i )
>{
>  static int k = i;
>}

Naja, das ist ja eigentlich das gleiche. Der Compiler reserviert vor 
main() Speicher und initialisiert mit Null (oder auch gar nicht). Und 
bei JEDEM Aufrug gibt es ne einfache Zuweisung von i an k. Wobei das 
natürlich den Sinn von static vollkommen aushebelt. Aber C ist ja 
ziemlich, hüstel flexibel ;-)

>(wenn die Initialisierung zb. eine Konstante ist). Aber konzeptionell
>findet die Initialisierung erst beim Funktionsaufruf statt, weil
>die Variable offiziell davor nicht existiert.

Konzeptionell ist ja schön und gut, aber es geht mir eher um die 
praktische Realisierung. Und dort echten Code reinzufummeln, welcher 
immer prüft, ob es der erste Aufruf ist, ist a) langsamer und b) braucht 
es  zusätzlichen Variablenspeicher.

>Aber natürlich gilt, die 'oberste Direktive der Optimierung',
>die 'as-if' Regel: Der Compiler darf alles machen und umstellen,
>solange das Programm die Optimierung nicht feststellen kann und
>die Programmlogik gleich bleibt.

Naja, das ist auch die graue Theorie, vor allem bei zeitkritischen 
Dingen im Embedded Bereich. Siehe

Beitrag "Schwerer Bug in AVR-GCC 4.1.1"

MfG
Falk

von Uhu U. (uhu)


Lesenswert?

Falk wrote:

> Konzeptionell ist ja schön und gut, aber es geht mir eher um die
> praktische Realisierung. Und dort echten Code reinzufummeln, welcher
> immer prüft, ob es der erste Aufruf ist, ist a) langsamer und b) braucht
> es  zusätzlichen Variablenspeicher.

Das wird definitiv so gemacht, daß eine interne bool-Variable angelegt 
wird, die vermerkt, ob die static-Variable schon initialisiert ist.

Wenn du das für unsinnigen Aufwand hälst, dann verkennst du einfach, daß 
kleine Schlampereien bei der Sprachimplementierung bei der Anwendung der 
Sprache verheerende Folgen haben, die viel Geld für Fehlerbehebung 
verschlingen und Code unportabel machen.

Auf der anderen Seite ist Rechnerleistung heute konkurrenzlos billig.

Im übrigen muß der Software-Entwickler natürlich wissen, was er tut - 
wie in deinem Fachgebiet auch.

>
>>Aber natürlich gilt, die 'oberste Direktive der Optimierung',
>>die 'as-if' Regel: Der Compiler darf alles machen und umstellen,
>>solange das Programm die Optimierung nicht feststellen kann und
>>die Programmlogik gleich bleibt.
>
> Naja, das ist auch die graue Theorie, vor allem bei zeitkritischen
> Dingen im Embedded Bereich. Siehe
>
> Beitrag "Schwerer Bug in AVR-GCC 4.1.1"

Das ist nicht graue Theorie, sondern Software-Engineering. Es mag sein, 
daß es noch einige Murks-Implementierungen in der Praxis gibt, aber die 
haben so keine Zukunft, weil auf Dauer zu teuer.

von Karl H. (kbuchegg)


Lesenswert?

Falk wrote:

>>void foo( int i )
>>{
>>  static int k = i;
>>}
>
> Naja, das ist ja eigentlich das gleiche. Der Compiler reserviert vor
> main() Speicher und initialisiert mit Null (oder auch gar nicht). Und
> bei JEDEM Aufrug gibt es ne einfache Zuweisung von i an k.

Jetzt willst dus aber wieder genau wissen :-)

OK, ok. Ich hätte die Funktion etwas umfangreicher machen sollen
1
void foo( int i )
2
{
3
  static int k = i;
4
5
  // Aktionenen in denen unter anderem k verändert werden kann
6
  // oder auch nicht. zb.
7
  k++;
8
9
  printf( "%d ", k );
10
}

Jetzt kann die Zuweisung von i an k nicht mehr jedesmal
beim Betreten gemacht werden. Wird die Funktion aufgerufen
1
void main()
2
{
3
  for( i = 0; i < 10; ++i )
4
    foo( 5 );
5
}

dann muss die Ausgabe lauten:
6 7 8 9 10 11 12 13 14 15

>
> Konzeptionell ist ja schön und gut, aber es geht mir eher um die
> praktische Realisierung. Und dort echten Code reinzufummeln, welcher
> immer prüft, ob es der erste Aufruf ist, ist a) langsamer und b) braucht
> es  zusätzlichen Variablenspeicher.

Ganz einfach: Benutze kein static in einer Funktion, wenn du nicht
bnereit bist, den Preis dafür zu zahlen.
Laut C Standard ist die vom Compiler zu implementierende Funktionalität
in diesem Fall: Variable wird beim ersten Aufruf erzeugt und kommt
das erste mal in den Scope. Danach existiert diese Variable weiter
bis das Programm beendet wird.
Wie der Compiler das macht, überlässt der Standard dem Compiler. Es
muss lediglich genau diese Funktionalität erfüllt sein, dann gilt
der Compiler in diesem Prüfpunkt als standardkonform.

>
>>Aber natürlich gilt, die 'oberste Direktive der Optimierung',
>>die 'as-if' Regel: Der Compiler darf alles machen und umstellen,
>>solange das Programm die Optimierung nicht feststellen kann und
>>die Programmlogik gleich bleibt.
>
> Naja, das ist auch die graue Theorie,

Von wegen. Das ist im C-Standard im wesentlichen genau so
festgeschrieben. Wenn ein Compiler das nicht so hält, dann ist
er kein C Compiler. So einfach ist das.

von Falk (Gast)


Lesenswert?

@ Uhu Uhuhu (uhu)

>Das wird definitiv so gemacht, daß eine interne bool-Variable angelegt
>wird, die vermerkt, ob die static-Variable schon initialisiert ist.

Na das werde ich demnächst mal auf dem GCC mit dem AVR ausprobieren.

>kleine Schlampereien bei der Sprachimplementierung bei der Anwendung der
>Sprache verheerende Folgen haben, die viel Geld für Fehlerbehebung
>verschlingen und Code unportabel machen.

Schon klar, es geht hier aber nciht um Schlamperei sondern um eine 
sinnvolle Optimierung.

>Auf der anderen Seite ist Rechnerleistung heute konkurrenzlos billig.

Du bist Softwerker? Und weil CPU-Leitung (vor allem im Embedded-Bereich) 
spottbillig ist, braucht man heute selbst für ein popeliges Solität 
unter Vista 3GHz++, 1GB RAM und ne 3D Karte. . . . :-)

Dass man nicht immer auf Teufel komm raus sparen sollte ist mir klar, 
ich will auch gar nicht Asembler hier wieder reinbringen. Aber 
andererseits darf eine Programmiersprache nicht ins akademische 
abdriften, wenn sie was leisten will.

>Im übrigen muß der Software-Entwickler natürlich wissen, was er tut -
>wie in deinem Fachgebiet auch.

Sicher, hat aber mit dem Problem hier wenig zu tun.

>Das ist nicht graue Theorie, sondern Software-Engineering. Es mag sein,
>daß es noch einige Murks-Implementierungen in der Praxis gibt, aber die
>haben so keine Zukunft, weil auf Dauer zu teuer.

Das A20 Gate im PC hat auch verdammt lange überlebt. Und ich will gar 
nicht wissen, wieviel Altlasten in diverse Sachen (Software/Hardware 
etc.) stecken und trotz hoher Kosten und Nachteile mitgeschleppt werden, 
weil niemand das Risiko eingehen will/kann, alte Zöpfe abzuschneiden. 
Never change a running system.

Nichts ist so langlebeig wie ein Provisorium.

;-)

MFG
Falk

von Falk (Gast)


Lesenswert?

@ Karl heinz Buchegger (kbuchegg)

>Jetzt willst dus aber wieder genau wissen :-)

Aber immer. ;-)

>OK, ok. Ich hätte die Funktion etwas umfangreicher machen sollen

>void foo( int i )
>{
>  static int k = i;

>  // Aktionenen in denen unter anderem k verändert werden kann
>  // oder auch nicht. zb.
>  k++;

>  printf( "%d ", k );
>}

>Jetzt kann die Zuweisung von i an k nicht mehr jedesmal
>beim Betreten gemacht werden. Wird die Funktion aufgerufen

OK, gekauft. Bleibt ncoh die Frage, wie das mit der Speicherverwaltung 
realisiert ist. Wird schon zum Programmstart Psiecherplatz reserviert 
(aber nicht initialisiert) oder wird das dynamisch zur Laufzeit gemacht. 
Aber das ist wahrscheinlich wie so vieles in C compilerabhängig ;-)

>Ganz einfach: Benutze kein static in einer Funktion, wenn du nicht
>bnereit bist, den Preis dafür zu zahlen.

Ist konsequent.

>Von wegen. Das ist im C-Standard im wesentlichen genau so
>festgeschrieben. Wenn ein Compiler das nicht so hält, dann ist
>er kein C Compiler. So einfach ist das.

Naja, auch auf die Gefahr hin, mich etwas weit aus dem Fenster zu 
lehnen. C ist und bleibt für mich trotz diverser Aufräumaktionen der 
letzten 10 Jahre immer noch ziemlich schwamming/hackermässig. Angefangen 
von den ursprünglich unscharf definierten Grössen für char/int/long (OK, 
gibts mittlerweile uint8_t etc.) über dutzende andere Konstruktionen, 
die IMHO keiner braucht aber mit denen man sich, auch als Profi, schön 
ins Knie schiessen kann. Jaja, ich hab früher viel in Pascal 
programmiert, schön war die Zeit ;-)

MFG
Falk

von yalu (Gast)


Lesenswert?

Reden wir jetzt eigentlich von C oder C++? Der OP Senmeis schrieb
etwas von C-Dateien. Die von Uhu Uhuhu und Karl heinz genannten
Beispiele
1
void f() {
2
   static int local_static = k();
3
   ...
4
}

und
1
void foo( int i )
2
{
3
  static int k = i;
4
}

sind C++ und kein C.

Zwischen C und C++ besteht ein Unterschied, was die Initialisierung
von statischen Variablen betrifft:

In C++ ist es so, wie Mathematiker geschrieben hat: Die static-
Variablen werden beim ersten Aufruf initialisiert, was zusätzlichen
Code für die die Entscheidung, ob der Aufruf der erste ist, erfordert.
Der GCC legt die Variable aber intelligenterweise ins .data, wenn der
Initialisierer eine Konstante ist. Dort wird sie bereits beim Laden
bzw. beim Starten des Programms initialisiert. Das spart Zeit und
Platz.

In C ist der Initialisierer einer statischen Variable immer konstant:

  "All the expressions in an initializer for an object that has static
  storage duration shall be constant expressions or string literals."

Deswegen ist es Jacke wie Hose, ob die Initialisierung beim Programm-
start oder beim ersten Aufruf der Funktion erfolgt. Effizienter ist
natürlich die Initialisierung beim Programmstart, weswegen der GCC es
genau so macht (alle anderen C-Compiler wahrscheinlich ebenso).

> Laut C Standard ist die vom Compiler zu implementierende
> Funktionalität in diesem Fall: Variable wird beim ersten Aufruf
> erzeugt und kommt das erste mal in den Scope. Danach existiert diese
> Variable weiter bis das Programm beendet wird.

Das ist in C++ so. In C anders:

  "An object whose identifier is declared with external or internal
  linkage, or with the storage-class specifier static has static
  storage duration. Its lifetime is the entire execution of the
  program and its stored value is initialized only once, prior to
  program startup."

von Mathematiker (Gast)


Lesenswert?

> Angefangen von den ursprünglich unscharf definierten Grössen
> für char/int/long

In dem Aspekt ist C aber nicht alleine. Es gibt einige gute Gründe 
dafür, die Bitzahl eines int nicht festzulegen. In manchen, durchaus 
sehr modernen, Sprachen hat ein int auf einer 32-Bit-Architektur sogar 
nur 31 oder 30 Bit. Die übriggebliebenen Bits können dadurch als Flag 
verwendet werden, was im Endeffekt zu schnellerem Code führt.

von Rolf Magnus (Gast)


Lesenswert?

> In manchen, durchaus sehr modernen, Sprachen hat ein int auf einer
> 32-Bit-Architektur sogar nur 31 oder 30 Bit.

Interessant ist es auch in GLSL (der "OpenGL shading language"). Da muß 
int mindestens 16 Bits für den Wert haben, aber ein Vorzeichen braucht 
es auch noch, also liegt die Mindestgröße bei 17 Bits.

von Uhu U. (uhu)


Lesenswert?

Falk wrote:
>>Das wird definitiv so gemacht, daß eine interne bool-Variable angelegt
>>wird, die vermerkt, ob die static-Variable schon initialisiert ist.
>
> Na das werde ich demnächst mal auf dem GCC mit dem AVR ausprobieren.

Viel Vergnügen! Nimm aber C++, sonst rastet der Compiler bei 
nicht-konstanten Initialisierungsausdrücken aus ;-)

>>kleine Schlampereien bei der Sprachimplementierung bei der Anwendung der
>>Sprache verheerende Folgen haben, die viel Geld für Fehlerbehebung
>>verschlingen und Code unportabel machen.
>
> Schon klar, es geht hier aber nciht um Schlamperei sondern um eine
> sinnvolle Optimierung.

Sinnvolle Optimierung kann hier nur heißen, daß der Compiler prüft, ob 
er den Initialisierungsausdruck zur Übersetzungszeit berechen kann. Wenn 
ja, kann die Variable in ein initialisiertes Datensegment gelegt werden, 
wenn nein, muß auf das beschriebene Verfahren zurückgegriffen werden.

>>Auf der anderen Seite ist Rechnerleistung heute konkurrenzlos billig.
>
> Du bist Softwerker?

Ja.

> Und weil CPU-Leitung (vor allem im Embedded-Bereich)
> spottbillig ist, braucht man heute selbst für ein popeliges Solität
> unter Vista 3GHz++, 1GB RAM und ne 3D Karte. . . . :-)

Wie gesagt: Der Entwickler muß wissen, was er tut. Zuweilen habe auch 
ich meine Zweifel, ob man das im Umkehrschluß auch gewissen Leuten 
unterstellen kann, die als Entwickler arbeiten.

> Dass man nicht immer auf Teufel komm raus sparen sollte ist mir klar,
> ich will auch gar nicht Asembler hier wieder reinbringen. Aber
> andererseits darf eine Programmiersprache nicht ins akademische
> abdriften, wenn sie was leisten will.

Eine Programmiersprache muß logisch und konsistent sein und den 
Denkgewohnheiten ihrer Benutzer entgegen kommen.

>>Im übrigen muß der Software-Entwickler natürlich wissen, was er tut -
>>wie in deinem Fachgebiet auch.
>
> Sicher, hat aber mit dem Problem hier wenig zu tun.

Das sehe ich anders. Wenn du einem Affen Bleistift und Papier gibst, 
kannst du auch nicht erwarten, daß hinterher fein säuberlich komponiert 
eine Fuge auf dem Blatt steht.

> Das A20 Gate im PC hat auch verdammt lange überlebt. Und ich will gar
> nicht wissen, wieviel Altlasten in diverse Sachen (Software/Hardware
> etc.) stecken und trotz hoher Kosten und Nachteile mitgeschleppt werden,
> weil niemand das Risiko eingehen will/kann, alte Zöpfe abzuschneiden.
> Never change a running system.
>
> Nichts ist so langlebeig wie ein Provisorium.

Na ja, das waren Kompromisse, die man an den Stand der damaligen 
Hardwaretechnik glaubte machen zu müssen und denen naturgemäß ein sehr 
langes und zähes Leben beschieden ist, je tiefer sie in einem über die 
Zeit weiterentwickelten Teil stecken - das ist in der biologischen 
Evolution auch nicht anders.

Erfolglose Projekte haben dieses Problem natürlich nicht...

Andersherum: Das A20-Gate ist ein Paradebeispiel dafür, daß man besser 
noch dreißig mal in sich gehen soll, bevor man solchen Mist auf die 
Menschheit losläßt.

von Uhu U. (uhu)


Lesenswert?

@ yalu:

Senmeis Beispielcode kann nur C++ sein, denn es ist kein gültiges C.

von Karl H. (kbuchegg)


Lesenswert?

yalu wrote:
>
> In C ist der Initialisierer einer statischen Variable immer konstant:
>
>   "All the expressions in an initializer for an object that has static
>   storage duration shall be constant expressions or string literals."
>

Ooops. Das wusste ich gar nicht.
Wieder was gelernt.
Da das in C++ definitiv nicht so ist, sinnvoll ist und auch nicht
schwer zu implementieren ist, bin ich eigentlich stillschweigend
davon ausgegangen, das waere von C so übernommen worden.

Mein Fehler.
Tut mir leid, wenn ich hier einen Wirbel hineingebracht habe.

von Falk (Gast)


Lesenswert?

@ Uhu Uhuhu (uhu)

>> Na das werde ich demnächst mal auf dem GCC mit dem AVR ausprobieren.

>Viel Vergnügen! Nimm aber C++, sonst rastet der Compiler bei
>nicht-konstanten Initialisierungsausdrücken aus ;-)

Naja, durch die Aufklärung, dass es sich dabei um C++ handelt hat es 
sich für mich eigentlich erledigt. Von C++ hab ich praktisch keinen 
Schimmer und im Moment und auf mittlere Sicht keinerlei Verwendung. Bin 
Hardwerker ;-)

>Wie gesagt: Der Entwickler muß wissen, was er tut. Zuweilen habe auch
>ich meine Zweifel, ob man das im Umkehrschluß auch gewissen Leuten
>unterstellen kann, die als Entwickler arbeiten.

Jaja, wie bei James Dean. "Denn sie wissen nciht was sie tun" ;-)

>Eine Programmiersprache muß logisch und konsistent sein und den
>Denkgewohnheiten ihrer Benutzer entgegen kommen.

JAIN!!! Sie muss aber in gewisser Weise auch den Programmierer erziehen 
und zu sauberer Arbeitsweise "zwingen". Und Mauscheln möglichst per se 
verhindern oder schwierig machen. Und was die "Logik" einiger Softwerker 
angeht, naja . . . UPN ist da noch harmlos ;-)

MfG
Falk

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


Lesenswert?

Karl heinz Buchegger wrote:

> Da das in C++ definitiv nicht so ist, sinnvoll ist und auch nicht
> schwer zu implementieren ist, bin ich eigentlich stillschweigend
> davon ausgegangen, das waere von C so übernommen worden.

Naja, wenn du mal in den generierten Code guckst, wirst du sehen,
dass der dafür notwendige Aufwand einiges größer ist als für den
in C zulässigen konstanten Intialisierer.  C++ braucht das Feature
einfach auf Grund der OO-Erfodernisse (ein Objekt muss sich zu
einer beliebigen Zeit erstellen lassen).

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.