Sorunuzu iki soru olarak yorumlayacağım: 1) neden ->var bile ve 2) neden .işaretçiyi otomatik olarak iptal etmiyor? Her iki soruya da cevapların tarihsel kökleri vardır.
Neden ->var?
C dilinin ilk sürümlerinden birinde ( Mayıs 1975'te 6. Baskı Unix ile birlikte gelen " C Referans Kılavuzu " için CRM olarak anacağım), operatör ->çok özel bir anlama sahipti, eş anlamlı değil *ve .kombinasyon
CRM tarafından tanımlanan C dili, birçok açıdan modern C'den çok farklıydı. CRM yapısında üyeler , herhangi bir adres kısıtlamasına tür kısıtlaması olmadan eklenebilecek küresel bayt uzaklığı kavramını uyguladılar . Yani, tüm yapı mensuplarının tüm adları bağımsız küresel anlamlara sahipti (ve bu nedenle, benzersiz olmak zorundaydı). Örneğin,
struct S {
int a;
int b;
};
ve ad aofset 0 için, ad ise bofset 2 anlamına gelir ( intboyut 2 tipi ve dolgu yok). Çeviri birimindeki tüm yapıların tüm üyelerinin benzersiz adları vardır veya aynı uzaklık değerini temsil eder. Örneğin, aynı çeviri biriminde ayrıca
struct X {
int a;
int x;
};
ve bu sorun olmaz, çünkü isim asürekli olarak 0 ofsetini temsil eder. Fakat bu ek deklarasyon
struct Y {
int b;
int a;
};
aofset 2 ve bofset 0 olarak "yeniden tanımlamaya" çalıştığından resmi olarak geçersiz olacaktır .
İşte bu noktada ->operatör devreye girer. Her yapı üyesi adının kendi kendine yeterli küresel anlamı olduğundan, dil bu gibi ifadeleri destekledi
int i = 5;
i->b = 42; /* Write 42 into `int` at address 7 */
100->a = 0; /* Write 0 into `int` at address 100 */
İlk atama olarak derleyici tarafından yorumlandı "take adresi 5, ofset ekleyin 2buna ve atamak için 42için intçıkan adreste değeri". Yani yukarıda atayın 42için intadreste değeri 7. Bu kullanımın ->sol taraftaki ifadenin türünü umursamadığını unutmayın . Sol taraf bir rvalue sayısal adresi olarak yorumlandı (bir işaretçi veya bir tam sayı olsun).
Bu tür bir hile *ve .kombinasyon mümkün değildi . Yapamazsın
(*i).b = 42;
çünkü *izaten geçersiz bir ifade. *Operatör, bu ayrıdır beri .kendi işlenen üzerine, yüklemektedir daha sıkı tip gereksinimleri. CRM, bu sınırlamanın üstesinden gelmek ->için sol operatörün türünden bağımsız olarak operatörü tanıttı .
Keith'in yorumlarda belirttiği gibi, ->ve *+ .kombinasyonu arasındaki bu fark , CRM'in 7.1.8'de "gereksinimin gevşemesi" olarak adlandırdığı şeydir: İşaretçi türü olan gereksinimin gevşemesi dışında E1, ifade E1−>MOStam olarak eşdeğerdir(*E1).MOS
Daha sonra, K&R C'de CRM'de başlangıçta açıklanan birçok özellik önemli ölçüde yeniden işlendi. "Global ofset tanımlayıcısı olarak yapı üyesi" fikri tamamen kaldırıldı. Ve ->operatörün işlevselliği *ve .kombinasyonunun işlevselliği ile tamamen aynı oldu .
.İşaretçiyi neden otomatik olarak iptal edemiyorsunuz ?
Yine, dilin CRM sürüm sol işlenen .operatörü bir olması gerekirdi lvalue . Bu işlenene uygulanan tek gereklilik buydu (ve ->yukarıda açıklandığı gibi onu farklı kılan da budur ). CRM ki Not değil sol işlenen gerektiren .bir yapı tipini olması. Sadece bir lvalue, herhangi bir lvalue olmasını gerektiriyordu . Bu, C'nin CRM sürümünde böyle bir kod yazabileceğiniz anlamına gelir
struct S { int a, b; };
struct T { float x, y, z; };
struct T c;
c.b = 55;
Bu durumda derleyici , tipte bir alan olmamasına rağmen , sürekli bellek bloğunda byte-offset 2'de konumlandırılmış 55bir intdeğere yazacaktır . Derleyici gerçek türünü hiç umursamaz . Tek ilgilendiği şey bir değerdi: bir tür yazılabilir bellek bloğu.cstruct Tbcc
Şimdi bunu yaparsanız
S *s;
...
s.b = 42;
kod geçerli sayılır ( sayrıca bir değer olduğu için) ve derleyici sadece bayt-offset 2'de işaretçinin skendisine veri yazmaya çalışacaktır. kendisini bu tür konularla ilgilendirmedi.
Yani dilin bu sürümünde, .işaretçi türleri için aşırı yükleme operatörü hakkında önerdiğiniz fikir işe yaramaz: operatör .işaretçilerle (değer değeri işaretçileriyle veya herhangi bir değerle) kullanıldığında çok özel bir anlama sahipti. Çok garip bir işlevsellikti, şüphesiz. Ama o sırada oradaydı.
Tabii ki, bu garip işlevsellik, .C - K&R C'nin elden geçirilmiş versiyonunda işaretçiler için aşırı yüklenen operatörün (önerdiğiniz gibi) tanıtımına karşı çok güçlü bir neden değil. Belki de o sırada C'nin CRM sürümünde desteklenmesi gereken bazı eski kodlar vardı.
(1975 C Başvuru Kılavuzu'nun URL'si sabit olmayabilir. Muhtemelen bazı küçük farklılıklar içeren başka bir kopya buradadır .)