2011-07-07 18 views
9

Korumam gereken bir projede tuhaf görünen bir kod parçası buldum. Derleyici hatasına yol açmayan bir sınıfın boş bir dizi üyesi var. Ben MSVC 10.0 ile böyle bir kod bazı varyasyonlarını test ettik: int i[] deBoş dizi bildirimi - garip derleyici davranışı

template<class T> struct A { 
    int i[]; 
}; // warning C4200: nonstandard extension used : zero-sized array in struct/union 

template<class T> struct B { static int i[]; }; 
template<class T> int B<T>::i[]; 

struct C { 
    int i[]; 
}; //warning C4200: nonstandard extension used : zero-sized array in struct/union 

template<class T> struct D { static int i[]; }; 
template<class T> int D<T>::i[4]; 
template<>  int D<int>::i[] = { 1 }; 


int main() 
{ 
    A<void> a; 
    B<void> b; 
    C c; 
    D<void> d0; 
    D<int> d1; 

    a.i[0] = 0;  // warning C4739: reference to variable 'a' exceeds its storage space 

    b.i[0] = 0;  // warning C4789: destination of memory copy is too small 

    c.i[0] = 0;  // warning C4739: reference to variable 'c' exceeds its storage space 

    int i[];  // error C2133: 'i' : unknown size 

    d0.i[0] = 0; // ok 
    d0.i[1] = 0; // ok 

    return 0; 
} 

hata mesajı bana kesinlikle mantıklı. D sınıfı ile gösterilen kod, iyi oluşturulmuş standart C++'dur. Ancak A, B vesınıflarına ne dersiniz? Bu sınıflarda üye değişkeni int i[] ne tür?

cevap

6

DÜZENLEME:

sizin şüphe yapılar/sendikaların sonunda sıfırın boyutlu diziler sağlar definition of the extension to the language, ile açıklanabilir. Denemedim, ancak sıfır boyutlu diziden sonra başka bir üye bildirirseniz başarısız olur.

, yığında bir değişken ayırırsanız, boyutunu bilmeniz gerekir; kuralın istisnası, bazı C-tipik hilelerin mümkün olduğu bir yapının/birleşimin sonunda bir dizinin tahsis edilmesidir.

C++ içinde bu, varsayılan kopya oluşturucusu ve atama işleci muhtemelen çalışmadığı için bir uyarı oluşturur.

ÖNCEKİ YANIT:

derleyici sıfır boyutu ile bir dizi tanımlamak çalışıyoruz gerçeği hakkında sizi uyarır. Bu standart C/C++ 'ye izin verilmez.

Sınıflara göre sınıf farklılıklarını görelim. Sınıf D'de

:

template<class T> struct D { static int i[]; };

sadece statik üyesi değişkenin türünü ilan çünkü işe yarıyor. Bu bağlamak için, ayrıca sizin gibi bir tanım açıklamada, asıl diziyi tanımlayan gerekir: Burada

template<>  int D<int>::i[] = { 1 }; 

da başlatıcısı yoluyla dizinin boyutu belirtin. Sınıf B ile

, benzer bir şey yapıyorsun, ama tanımı şöyledir:

template<class T> int B<T>::i[]; 

yani sen boyutu belirtmek ve uyarı alamadım.

A sınıfı ile, daha fazlası, boyutsuz bir tür dizisi üye değişkeni tanımlıyorsunuz.

+0

Soru şu: Hatalar yerine (A ',' B' ve 'C' sınıfları uyarıları ile ilgili uyarılar neden)? Benim görüşüme göre bu, yerel değişkenin beyanı üzerine aldığım hata ile kıyaslandığında asimetriktir. – 0xbadf00d

+0

Düzenlememe bakın, lütfen. – sergio

+0

Teşekkürler, C++ standardına başka bir "güzel" Microsoft Eklentisi ... – 0xbadf00d

0

İyi bir tane. Sadece emin olmak için, derleyicinin neden bir hata olarak işaretlemediğini merak ediyorsunuz? Bu durumda, derleyicide bu sorunun tahmin edilemez olduğunu düşünüyorum, ancak MSVC'de bu durumun her zaman farkındayım.

http://support.microsoft.com/kb/98409

Onların yaptığı gibi açıklayabilirim bakayım.Ben, böyle boş bir dizi ile bir yapı bildirmek için olsaydı

struct a 
{ 
    int x; 
    char empty[]; 
}; 

derleyici Char işaretçisi x 4 bayt ve muhtemelen başka 4 bayt ayırabilir. boş yapı a başlangıcını geçtikten sonra 4 bayt adres içerecektir. Uzunluğun bir karakter dizisi olduğundan, erişmeye çalıştığınızda, dizenin sonunu belirtmek için 0 sonu olmadığından bir hata olur.

Bu hatanın üstesinden gelmek için yapıyı daha sonra gerçek bir dizenin başlangıcına işaret edecek şekilde başlatabilirim.

struct a myStruct = { 1, "hello world"}; // empty now points to the start of "hello world" 

bir yapı temelde bir sınıf olduğundan

, sen onun bir agrega ve tam bir sınıf emin olun eğer bir sınıf ile aynı şeyi yapabilirsiniz çıkıyor. O halde işte gidiyorsunuz. MSVC derleyicileri, bir struct/class içinde bildirildiğinde işaretçi olarak sabit boyutlu olmayan dizileri işlemektedir. Sınıf tanımlarının sadece beyanlar olduğunu unutmayın. Derleyici, bunun için bir örnek oluşturana kadar onlar için alan ayırmaz. Bunu düşünmeye başladığınızda, o zamandan beri sorta yapar. Derleyici, daha sonra depolamayı ayırmayı planlıyorsanız nasıl bilecek? Bir çalışma zamanı artefaktı olur ama derleyici hala sorun hakkında sizi uyarmaya yetecek kadar akıllıydı.