Hallo TS,
hui, da ist man mal kurz nicht da...
Aus meiner Sicht ist eine static-Variable in einer Funktion Syntaxzucker für eine globale Variable, die nur im Scope dieser Funktion angesprochen werden darf.
Ob ich nun (in C) programmiere:
int foo = 0;
void bar() {
foo = foo + 1;
}
oder
void bar() {
static int foo = 0;
foo = foo + 1;
}
sollte von der Wirkungsweise her keinen Unterschied machen (solange Rolf und Herr B sich einig sind, dass foo nur von bar() verwendet werden darf).
Ich habe das mal ausprobiert. Auf meinem Visual Studio habe ich die C/C++ Workload nicht aktiviert, aber es gibt ja Online Compiler mit Assembler-Ausgabe.
Das ist mein Test: Es gibt drei Variablen, bar1, bar2 und bar3. bar1 ist global static - was letztlich nur dazu führt, dass das Symbol bar1 für den Linker nicht sichtbar ist. bar2 ist global, und bar3 ist local static.
static int bar1 = 0;
int bar2 = 0;
int sumUp(int num) {
static int bar3 = 0;
return bar3 += num;
}
Ich habe jetzt dreimal compiliert, mit dem Unterschied, dass ich in der return-Zeile nacheinander bar1, bar2 und bar3 eingesetzt habe. Compiler war x86-64 gcc 9.2
sumUp:
push rbp
mov rbp,rsp
mov DWORD PTR [rbp-0x4],edi
mov edx,DWORD PTR [rip+0x200b1d] # 60102c <bar1>
mov eax,DWORD PTR [rbp-0x4]
add eax,edx
mov DWORD PTR [rip+0x200b12],eax # 60102c <bar1>
mov eax,DWORD PTR [rip+0x200b0c] # 60102c <bar1>
pop rbp
ret
sumUp:
push rbp
mov rbp,rsp
mov DWORD PTR [rbp-0x4],edi
mov edx,DWORD PTR [rip+0x200b21] # 601030 <bar2>
mov eax,DWORD PTR [rbp-0x4]
add eax,edx
mov DWORD PTR [rip+0x200b16],eax # 601030 <bar2>
mov eax,DWORD PTR [rip+0x200b10] # 601030 <bar2>
pop rbp
ret
sumUp:
push rbp
mov rbp,rsp
mov DWORD PTR [rbp-0x4],edi
mov edx,DWORD PTR [rip+0x200b25] # 601034 <bar3.1910>
mov eax,DWORD PTR [rbp-0x4]
add eax,edx
mov DWORD PTR [rip+0x200b1a],eax # 601034 <bar3.1910>
mov eax,DWORD PTR [rip+0x200b14] # 601034 <bar3.1910>
pop rbp
ret
Es ist immer der gleiche Code, nur die Adressen unterscheiden sich um jeweils 4 Bytes. Er addressiert IP-relativ, na gut. Klingt nach Memory Model tiny oder small.
Der MSVC zeigt es noch schöner:
PUBLIC _bar2
_BSS SEGMENT
_bar1 DD 01H DUP (?)
_bar2 DD 01H DUP (?)
?bar3@?1??sumUp@@9@9 DD 01H DUP (?) ; `sumUp'::`2'::bar3
_BSS ENDS
PUBLIC _sumUp
_TEXT SEGMENT
_num$ = 8 ; size = 4
_sumUp PROC
push ebp
mov ebp, esp
mov eax, DWORD PTR ?bar3@?1??sumUp@@9@9
add eax, DWORD PTR _num$[ebp]
mov DWORD PTR ?bar3@?1??sumUp@@9@9, eax
mov eax, DWORD PTR ?bar3@?1??sumUp@@9@9
pop ebp
ret 0
_sumUp ENDP
_TEXT ENDS
bar1, bar2 und bar3 unterscheiden sich nur darin, ob sie public sind oder nicht, und ob der Name vermangelt wird. Sie liegen alle 3 hintereinander im BSS Segment. static in einer Funktion ist Syntaxzucker, weiter nichts.
Aber: Das ist C/C++. In anderen Sprachen mag es anders realisiert sein. PHP ist so dynamisch - ich traue den Brüdern zu, dass sie ein internes Flag setzen, das angibt ob die Initialisierung schon gelaufen ist. Wobei das auch in PHP nicht wichtig ist, weil der Initializer-Ausdruck konstant sein muss.
Rolf
sumpsi - posui - clusi