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 a
ofset 0 için, ad ise b
ofset 2 anlamına gelir ( int
boyut 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 a
sürekli olarak 0 ofsetini temsil eder. Fakat bu ek deklarasyon
struct Y {
int b;
int a;
};
a
ofset 2 ve b
ofset 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 2
buna ve atamak için 42
için int
çıkan adreste değeri". Yani yukarıda atayın 42
için int
adreste 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ü *i
zaten 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−>MOS
tam 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ış 55
bir int
değ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.c
struct T
b
c
c
Şimdi bunu yaparsanız
S *s;
...
s.b = 42;
kod geçerli sayılır ( s
ayrıca bir değer olduğu için) ve derleyici sadece bayt-offset 2'de işaretçinin s
kendisine 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 .)