Kod:
int tab[6] = {0}
Czy ZAWSZE jest pewność, że cała tablica będzie wyzerowana, czy nie jest to czasem kwestia kompilatora, dialektu języka czy czegokolwiek innego. Czy istnieje chodź najmniejsza szansa, że od [1..5] dostaniemy jakieś losowe dane (takie co leżały tam wcześniej w pamięci)?
Pytanie uznałem za ciekawe, szczególnie, że niby wiedziałem jak to działa, ale nigdy nie uznałem za stosowne się upewnić (tj. zajrzeć do standardu czy też sprawdzić na różnych wersjach GCC lub innych kompilatorów). Poniżej publikuje moją odpowiedź:
--quote--
Ad meritum, domyślam się, że chodzi o tablicę lokalną (gdyż w innych przypadkach tablica ta będzie wyzerowana niezależnie od jej inicjacji... hmm, ale nie jestem tu pewien co do tablic globalnych/lokalnych względem threadu (TLS)).
Kilka testów empirycznych:
gcc w wersji 4.4.1 x86-64 zeruje całą tablicę:
gcc w wersji 4.3.4 x86-64 zeruje całą tablicę:
mov QWORD PTR [rbp-48], 0
mov QWORD PTR [rbp-40], 0
mov QWORD PTR [rbp-32], 0
gcc w wersji 2.95.4 x86 zeruje całą tablicę:
leal -24(%ebp),%edi
xorl %eax,%eax
cld
movl $6,%ecx
rep
stosl
gcc w wersji 3.4.6 x86 zeruje całą tablicę:
lea %edi, [%ebp-40]
cld
mov %edx, 0
mov %eax, 6
mov %ecx, %eax
mov %eax, %edx
rep stosd
gcc w wersji 4.1.2 x86 zeruje całą tablicę:
lea %eax, [%ebp-28]
mov %edx, 0
mov DWORD PTR [%eax], %edx
add %eax, 4
mov DWORD PTR [%eax], %edx
add %eax, 4
mov DWORD PTR [%eax], %edx
add %eax, 4
mov DWORD PTR [%eax], %edx
add %eax, 4
mov DWORD PTR [%eax], %edx
add %eax, 4
mov DWORD PTR [%eax], %edx
Microsoft 32-bit C/C++ Optimizing Compiler w wersji 15.00.30729.01 zeruje tablice:
; Line 14
mov DWORD PTR _tab$[ebp], 0
xor eax, eax
mov DWORD PTR _tab$[ebp+4], eax
mov DWORD PTR _tab$[ebp+8], eax
mov DWORD PTR _tab$[ebp+12], eax
mov DWORD PTR _tab$[ebp+16], eax
mov DWORD PTR _tab$[ebp+20], eax
OK, to teraz trzeba rzucić okiem w standardy C, co one tam piszą:
ISO/IEC 9899:1999 (Second edition, 1999-12-01) paragraf 6.7.8, punkt 21:
If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.
Warto tu zacytować punkt 10 z tego samego paragrafu:
[...] If an object that has static storage duration is not initialized explicitly, then:
[...]
- if it has arithmetic type, it is initialized to (positive or unsigned) zero;
Czyli, wynika z tego, że standard nakazuje kompilatorowi wyzerowanie pozostałych elementów tablicy.
Rzucę jeszcze okiem na najnowszą wersję C99 i na C89 aka ANSI C...
Najpierw C89 (kurcze, nie wiem którą wersję mam), paragraf 3.5.7
If an object that has static storage duration is not initialized explicitly, it is initialized implicitly as if every member that has arithmetic type were assigned 0 and every member that has pointer type were assigned a null pointer constant.
[...]
If there are fewer initializers in a list than there are members of an aggregate, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.
Czyli tak samo jak z C99.
Z tego co widzę, to w najnowszym dostępnym standardzie C99 (http://open-std.org/JTC1/SC22/WG14/www/docs/n1336.pdf) nic nie zmienili w tym punkcie w stosunku do wersji cytowanej przeze mnie na początku :)
Podsumowując: jeżeli kompilator trzyma się standardu w tym punkcie, to jest pewność, że tablica będzie wyzerowana.
Zarówno GCC we wszystkich wersjach testowanych przeze mnie jak i MS C/C++ compiler (aka Visual C++) trzymają się w tym punkcie standardu :)
--end of quote--
A nuż się komuś przyda :)
Comments:
#include <stdio.h>
int main() {
int tab[6] = {1};
printf("tab[0] = %d
", tab[0]);
printf("tab[1] = %d
", tab[1]);
printf("tab[5] = %d
", tab[5]);
return 0;
}
Na wartość 1 inicjalizowany jest tylko pierwszy element. Program wypisze co następuje:
tab[0] = 1
tab[1] = 0
tab[5] = 0
(Sprawdzone na gcc 4.1.1)
"Za równo GCC" ma być - zarówno.
A obiecywałeś poprawę::
2010-01-28 02:23:41 = Gynvael Coldwind
{
@rinz
Thx, postaram się zapamiętać :)
(lub dodać "disclaimer" a propos drobnych błędów w pisowni ;p)
}Sry
Haha np i thx za ciekawe pytanie :)
@Pafi
Thx, masz rację, podany przez Ciebie przykład nawet lepiej ilustruje co się dzieje :)
@dd3s
Mea culpa! W ramach zadośćuczynienia znalazłem 3 "za równo" na blogu i poprawiłem :)
W każdym bądź razie, w C++ reguła brzmi nieco inaczej (8.5.1):
"If there are fewer initializers in the list than there are members in the aggregate, then each member not
explicitly initialized shall be value-initialized (8.5)."
Znaczenie "value-initialization" zaś jest takie:
"To value-initialize an object of type T means:
— if T is a class type (clause 9) with a user-declared constructor (12.1), then the default constructor for T is
called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is a non-union class type without a user-declared constructor, then every non-static data member
and base-class component of T is value-initialized;
— if T is an array type, then each element is value-initialized;
— otherwise, the object is zero-initialized
A program that calls for default-initialization or value-initialization of an entity of reference type is ill-
formed. If T is a cv-qualified type, the cv-unqualified version of T is used for these definitions of zero-
initialization, default-initialization, and value-initialization."
Czyli generalnie wychodzi na to samo - PODy inicjalizowane zerami, pozostałe rzeczy konstruktorem domyślnym.
Add a comment: