Bilgi gizleme
İşlevin geri dönüş bildiriminde tüm yapıyı döndürmenin aksine bir göstericiyi bir yapıya döndürmenin avantajı nedir?
En yaygın olanı bilgi gizlemedir . C, struct
özel bir alan oluşturma yeteneğine sahip değil, onlara erişmek için yöntemler sağlasa bile.
Bu nedenle, geliştiricilerin bir pointee'nin içeriğini görmesini ve kurcalamasını zorla engellemek istiyorsanız FILE
, o zaman tek ve tek yol, işaretçiyi pointee büyüklüğü ve tanımı dış dünya tarafından bilinmiyor. O zaman tanım, FILE
yalnızca tanımını gerektiren işlemleri yapanlara fopen
görünürken, sadece yapı bildirimi kamu başlığına görünür.
İkili Uyumluluk
Yapı tanımını gizlemek, dylib API'lerde ikili uyumluluğu korumak için nefes alma odası sağlamaya da yardımcı olabilir. Kütüphane uygulayıcılarının saydamlık yapısındaki alanları, kütüphaneyi kullananlarla ikili uyumu bozmadan değiştirebilmelerini sağlar, çünkü kodlarının niteliğinin yalnızca yapıyla ne yapabileceklerini, ne kadar büyük olduklarını bilmeleri gerekir var.
Örnek olarak, bugün Windows 95 döneminde inşa edilmiş bazı eski programları çalıştırabilirim (her zaman mükemmel değil, ama şaşırtıcı bir şekilde hala çalışıyor). Muhtemelen, bu eski ikili dosyaların bazı kodlarında, boyutu ve içeriği Windows 95 döneminden değişmiş yapılara opak işaretçiler kullanılmış. Yine de programlar, bu yapıların içeriğine maruz kalmadığından yeni pencerelerde çalışmaya devam ediyor. İkili uyumluluğun önemli olduğu bir kitaplıkta çalışırken, müşterinin maruz kalmadığı şeylerin genellikle geriye dönük uyumluluktan kaçmadan değişmesine izin verilir.
verim
NULL olan bir tam yapı döndürmek, sanırım daha zor ya da daha az verimli olacaktır. Bu geçerli bir sebep mi?
Tipik olarak malloc
halihazırda tahsis edilmiş değişken boyutlu bir ayırıcı havuz hafızasından ziyade, sabit bir boyutta olduğu gibi , sahnelerin arkasında kullanılan tipik olarak çok daha az genelleştirilmiş bir bellek ayırıcısı olmadıkça, türün pratik olarak sığabileceği ve istifte tahsis edilebileceği varsayımıyla daha az verimlidir . Bu durumda, büyük olasılıkla, kütüphane geliştiricilerinin ilgili ile ilgili değişmezleri (kavramsal garantileri) korumalarına izin vermek bir güvenlik riskidir FILE
.
En azından performans açısından, fopen
göstericiyi geri döndürmek bu kadar geçerli bir neden değildir çünkü döndürdüğü tek neden NULL
bir dosyayı açmamaktır. Bu, tüm genel durum yürütme yollarını yavaşlatmak karşılığında olağanüstü bir senaryoyu optimize etmek olacaktır. Bazı durumlarda tasarımları daha kolay hale getirmek NULL
için bazı post-koşullarında iade edilmelerine izin vermek için işaretçilere geri dönmelerini sağlamak için geçerli bir verimlilik nedeni olabilir .
Dosya işlemleri için, ek yükler dosya işlemlerinin kendilerine göre oldukça önemsizdir ve el kitabından fclose
yine de kaçınılması gerekmez . Bu nedenle, istemciyi, bir yığın tahsisini önlemek için dosya işlemlerinin göreceli maliyeti göz önüne alındığında, tanımını FILE
göstererek ve değerine göre geri döndürerek kaynağı serbest bırakma (kapatma) zorluğundan kurtarmamız gibi bir şey değil. fopen
.
Sıcak Noktalar ve Düzeltmeler
Yine de, diğer durumlarda, malloc
bu uygulamanın opak işaretçilerle çok sık kullanılması ve bazen yığın halinde gereksiz yere çok fazla şey tahsis edilmesi sonucunda, eski kod tabanlarında sıcak noktalara ve gereksiz önbellek eksikliklerine neden olan eski kod tabanlarında bir sürü israf C kodu belirledim. büyük döngüler.
Bunun yerine kullandığım alternatif bir uygulama, başka kimsenin alanlara dokunmaması gerektiğini bildirmek için bir adlandırma kuralı standardı kullanarak, istemcinin kurcalamadığı durumlarda bile yapı tanımlarını ortaya koymaktır:
struct Foo
{
/* priv_* indicates that you shouldn't tamper with these fields! */
int priv_internal_field;
int priv_other_one;
};
struct Foo foo_create(void);
void foo_destroy(struct Foo* foo);
void foo_something(struct Foo* foo);
Gelecekte ikili uyumluluk kaygıları varsa, o zaman bunun gibi sadece fazladan bir miktar fazladan alan ayırmayı yeterince iyi buldum.
struct Foo
{
/* priv_* indicates that you shouldn't tamper with these fields! */
int priv_internal_field;
int priv_other_one;
/* reserved for possible future uses (emergency backup plan).
currently just set to null. */
void* priv_reserved;
};
Bu ayrılmış alan biraz boşa harcanır, ancak ileride Foo
kütüphanemizi kullanan ikili dosyaları bozmadan daha fazla veri eklememiz gerekirse, hayat kurtarıcı olabilir .
Bana göre, bilginin gizlenmesi ve ikili uyumluluk tipik olarak, değişken uzunluklu yapıların yanı sıra yapıların sadece yığın tahsisine izin vermesinin tek iyi nedenidir; Yığın üzerinde VLA tahsis etmek için VLA biçiminde hafıza). Büyük yapılar bile yazılımın yığındaki sıcak bellekle çok daha fazla çalıştığı anlamına gelirse değere göre daha ucuza gelir. Ve yaratılışta değerine göre geri dönmek daha ucuz olmasalar bile, bir kişi bunu basitçe yapabilirdi:
int foo_create(struct Foo* foo);
...
/* In the client code: */
struct Foo foo;
if (foo_create(&foo))
{
foo_something(&foo);
foo_destroy(&foo);
}
... Foo
gereksiz bir kopya olasılığı olmadan yığından başlatmak . Veya müşteri Foo
, bir nedenden ötürü istese bile öbek üzerinde tahsis etme özgürlüğüne bile sahiptir .