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).
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 –
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