2010-05-12 21 views
6

Nesnenin (c) nesnesinin (örneğin, aynı dosyadaki sınıfın yeniden sınıflandırılması değil, aynı sınıfın diff ivarlarla adlandırılması) çakışan tanımlarım olduğunda, hiçbir uyarıcı veya daha iyi hata henüz derleyici tarafından verilmez. Ivars her iki seti karşılık gelen dosyalarda uygun yöntemlerle kullanışlı olan MeselaGCC derleyici - hata veya belirtilmemiş davranış?

Foo.m.

@interface foo { 
int a; 
} 
- (int)method; 
@end 

@implementation foo 

- (int)method { 
    return a; 
} 

@end 

Bar.m:

@interface foo { 
float baz; 
} 

@end 

@implementation foo (category) 
- (float)blah { 
    return baz; 
} 
@end 

uyarılar veya hatasız derler. mı Bu kasıtlı? Bu kontrol edilmemiş bir hata mı? (Kayıt, a ve baz için aslında aynı bellek konumu vardır.)

Düzenleme: Ben 64 bit MacOS

cevap

18

Açıkça kırılmış olsa da, kodunun kodunun tüm durumlarda uyarı vermeden derlenmesi, derleyicinin nasıl uyarılacağını bilmesi için yeterli bilgiye sahip olmamasıdır. Doğru bir şekilde derlendiğinde, yalnızca 64-bit'te (doğrudan kırılgan olmayan ivarlardan değil, yeni Objective-C ABI'den fallout olan) tamamen farklı bir linker hatası üretir.

int main() {}, foo.m dosyasına ekler ve gcc -arch x86_64 foo.m -lobjc komut satırı ile derlerse, link hataları giderilir, çünkü nesne çalışma zamanı kitaplığı bağlantıyı tamamlamak için gerekli boş vtable sembollerini sağlar. Derleme sırasında her bir .m dosyasını yalıtılmış bir derleme birimi olarak düşünün. Derleyici bir .m dosyası derlediğinde, yalnızca bu .m dosyasında ne olduğu, bu .m dosyasında içe aktarılan herhangi bir şey tarafından sağlanan bilginin ve - bir projenin bunun için yapılandırılmış olması halinde - neyin projenin önceden derlenmiş başlığı. Böylece

, sen bar.m içinde derken:

@interface foo { 
float baz; 
} 

@end 

@implementation foo (category) 
- (float)blah { 
    return baz; 
} 
@end 
int main() {} 

derleyici foo.m. içinde bildiriminde bir bağı yoktur Oluşturulan kod, ivar bazına erişen sınıftaki bir kategoriyi tanımlar. o sınıf bağlantı zaman yoksa, bir hata, Asistan'da atmış yukarıdaki gibi bir ana fonksiyonu benim ilave ile foo.m ve bar.m verilecek, biraz farklı derlemeleri deneyelim:

gcc -arch i386 foo.m -lobjc 
Undefined symbols: 
    "_main", referenced from: 
     start in crt1.10.6.o 
ld: symbol(s) not found 
collect2: ld returned 1 exit status 

Anlamlıdır, çünkü foo.m.'da bir main() işlevi tanımlamamıştık. 64 bit derleme aynı şeyi yapar.

gcc -arch i386 bar.m -lobjc 

derler ve uyarmadan bağlar.

nm -a a.out 
00001f52 t -[foo(category) blah] 
00000000 A .objc_category_name_foo_category 

Yani, ikili sınıfına foo üzerinde category adında bir kategori içerir: (a düzine ilgisiz olanlar hakkında silinmiş) oluşturulan semboller bakmak, neden anlamak için. Bağlayıcı aslında kategorileri çözümlemeyi denediğinden bağlantı hatası yok. Kategori çalışma zamanında çözülmeden önce foo sınıfının sihirli olarak görüneceğini varsayar.

Bir Ivar ile çalışma zamanının sınıf/kategori çözünürlük ile birlikte takip edebilirsiniz:

env OBJC_PRINT_CLASS_SETUP=YES ./a.out 
objc[498]: CONNECT: pending category 'foo (category)' 
objc[498]: CONNECT: class 'Object' now connected (root class) 
objc[498]: CONNECT: class 'Protocol' now connected 
objc[498]: CONNECT: class 'List' now connected 

Yani, kategori beklemede olarak işaretlenmiş. Çalışma zamanı, foo devreye girer girmez bağlantı kuracaktır! Modern Objective-C ABI aslında doğru semboller ekleyerek meta verileri de dahil çeşitli nedenlerden için örnek değişkenleri ve kategorileri için yayılan neden olur çünkü

Şimdi, 64 bit ...

gcc -arch x86_64 bar.m -lobjc 
Undefined symbols: 
    "_OBJC_IVAR_$_foo.baz", referenced from: 
     -[foo(category) blah] in ccvX4uIk.o 
    "_OBJC_CLASS_$_foo", referenced from: 
     l_OBJC_$_CATEGORY_foo_$_category in ccvX4uIk.o 
     objc-class-ref-to-foo in ccvX4uIk.o 
ld: symbol(s) not found 

bağlantı hataları

vardır Bu, programları doğrulamaya yardımcı olabilir (bu durumda olduğu gibi).

Hiçbir derleme hatası (doğru davranış) ve bağlantı hataları anlamsız. Şimdi, ikisini birbirine bağlamaya ne dersin?

32 bitlik durumda, her şey derlenmez ve hata olmadan bağlanır. Böylece, ne olup bittiğini görmek için kusmak sembollere ve objc ayıklama bakmak gerekir:

gcc -arch i386 bar.m foo.m -lobjc 
nm -a a.out 
00001e0f t -[foo method] 
00001dea t -[foo(category) blah] 
00000000 A .objc_category_name_foo_category 
00003070 S .objc_class_name_foo 
env OBJC_PRINT_CLASS_SETUP=YES ./a.out 
objc[530]: CONNECT: attaching category 'foo (category)' 
objc[530]: CONNECT: class 'Object' now connected (root class) 
objc[530]: CONNECT: class 'Protocol' now connected 
objc[530]: CONNECT: class 'List' now connected 
objc[530]: CONNECT: class 'foo' now connected (root class) 

Aha! Şimdi bir sınıf foo var ve çalışma zamanı, başlangıçta kategoriyi sınıfa bağlar. Açıkçası, baz ivarını döndüren yöntem muhteşem bir şekilde başarısız olacak.

64 bit bağlayıcı olsa da, başarısız:

örnek değişkenleri için sembollerin eklenmesiyle
gcc -arch x86_64 bar.m foo.m -lobjc 
Undefined symbols: 
    "_OBJC_IVAR_$_foo.baz", referenced from: 
     -[foo(category) blah] in ccBHNqzm.o 
ld: symbol(s) not found 
collect2: ld returned 1 exit status 

, şimdi @interface yapıldığı gibi bir sınıf (yanlış redeclared edilmiştir durumları yakalamak bağlayıcı bar.m).

+0

orijinal soruma göre: bu, kasıtlı bir davranış mı yoksa derleyicinin denetlenmeyen bir hatasında mıdır? Ayrıca, iPad için olmak, bu 'modern' çalışma zamanında test ediliyor, fakat simülatörde, yani aslında i386 anlamına geliyor, bu yüzden yukarıda tanımlandığı gibi 64bit kuralları veya 32bit kurallarını takip etmelisiniz (eski çalışma zamanı) ve daha da önemlisi, bu cihazda değişecek mi? Ve son olarak, baz ivarın geri dönmesiyle ilgili olarak, bir –

+0

değerinin ortaya çıkardığı gibi, * (int *) & baz ile kanıtlandığı gibi, aynı bellek konumuna sahip olduğu için muhteşem bir arıza meydana gelmez. Uyarı yapmadan yapılabilmeli ve derlemeliyiz. Bu, 64 bit masaüstü derlemesinde ve cihazı hedeflerken bir bağlantı hatasına neden olur, ancak simülatörde ince (ama hatalı şekilde) bağlantı kuracaktır. Eğer hem 'hem' hem de 'a' değerlerini depolayabileceğinizi düşünüyorsanız, simülatörün çalışma zamanı altında iki tanesi etkin bir şekilde depolama alanını paylaşır. – bbum

0

Bence aynı çalışma zamanını kullanır inanıyoruz iPhone OS, bahsediyorum kayıt için Yaptığınız şey, extended sınıfı.

İlgili konular