Böyle bir kodun birçok avantajı olabilir, ancak maalesef C Standardı bunu kolaylaştırmak için yazılmamıştır. Derleyiciler tarihsel olarak Standardın gerektirdiği şeyin ötesinde, bu kodun Standart C'de mümkün olandan çok daha temiz bir şekilde yazılmasını mümkün kılan etkili davranışsal garantiler sundu, ancak derleyiciler son zamanlarda bu garantileri optimizasyon adına iptal etmeye başladı.
En dikkat çekici olarak, birçok C derleyicisi tarihsel olarak (belgeleme değilse tasarım gereği), iki yapı tipi aynı başlangıç dizisini içeriyorsa, türler ilgisiz olsa bile, bu ortak dizinin üyelerine erişmek için her iki türden bir işaretçinin kullanılabileceğini garanti etmiştir. ve ayrıca, ortak bir başlangıç sekansı oluşturmak amacıyla, yapılara yönelik tüm göstergeler eşdeğerdir. Böyle bir davranışı kullanan kod, kullanmayan koddan çok daha temiz ve daha güvenli olabilir, ancak ne yazık ki Standart, ortak bir başlangıç sırasını paylaşan yapıların aynı şekilde düzenlenmesini gerektirse de, kodun gerçekten kullanılmasını yasaklar bir diğerinin başlangıç sırasına erişmek için bir tür işaretçi.
Sonuç olarak, C'ye nesne yönelimli kod yazmak istiyorsanız, C'nin işaretçi türü kurallarına uymak için çok fazla çembere atlamaya karar vermeniz (ve bu kararı erkenden vermeniz gerekir) ve modern derleyiciler, eski derleyiciler istendiği gibi çalışan bir kod üretmiş olsa bile, kayıyorsa saçma sapan kod üretir veya kodun yalnızca eski stil işaretçi davranışını destekleyecek şekilde yapılandırılmış derleyicilerle (örn. Bazı insanlar "-fno-katı-aliasing") Bazı insanlar "-fno-katı-aliasing" i kötülük olarak görürler, ancak "-fno-katı-aliasing" C'yi bir dil olarak düşünmenin daha yararlı olacağını söyleyebilirim. bazı amaçlar için "standart" C'den daha büyük anlamsal güç sunar,ancak başka amaçlar için önemli olabilecek optimizasyonlar pahasına.
Örneğin, geleneksel derleyicilerde, tarihsel derleyiciler aşağıdaki kodu yorumlayacaktır:
struct pair { int i1,i2; };
struct trio { int i1,i2,i3; };
void hey(struct pair *p, struct trio *t)
{
p->i1++;
t->i1^=1;
p->i1--;
t->i1^=1;
}
aşağıdaki adımları sırayla gerçekleştirerek: ilk üyesini artırın, ilk üyenin *p
en düşük bitini tamamlayın *t
, ardından ilk üyesini azaltın ve ilk üyesinin *p
en düşük bitini tamamlayın *t
. Modern derleyiciler, işlem sırasını farklı nesneler için daha verimli olacak p
ve t
tanımlayacak bir kodla yeniden düzenler , ancak yapmazlarsa davranışı değiştirir.
Bu örnek elbette kasıtlı olarak konfirme edilmiştir ve pratikte, başka bir türün ortak başlangıç sırasının bir parçası olan üyelere erişmek için bir tür işaretçiyi kullanan kod genellikle işe yarayacaktır, ancak ne yazık ki böyle bir kodun ne zaman başarısız olabileceğini bilmenin bir yolu yoktur. tür temelli örtüşme analizini devre dışı bırakmak dışında hiç güvenli bir şekilde kullanmak mümkün değildir.
İki işaretçi rasgele tiplere takas gibi bir şey yapmak için bir işlev yazmak isterse daha az çelişkili bir örnek ortaya çıkabilir. "1990'ların C" derleyicilerinin büyük çoğunluğunda, bu şu şekilde gerçekleştirilebilir:
void swap_pointers(void **p1, void **p2)
{
void *temp = *p1;
*p1 = *p2;
*p2 = temp;
}
Bununla birlikte Standart C'de, aşağıdakileri kullanmak gerekir:
#include "string.h"
#include "stdlib.h"
void swap_pointers2(void **p1, void **p2)
{
void **temp = malloc(sizeof (void*));
memcpy(temp, p1, sizeof (void*));
memcpy(p1, p2, sizeof (void*));
memcpy(p2, temp, sizeof (void*));
free(temp);
}
Eğer *p2
tahsis depoda tutulur ve geçici işaretçi tahsis depoda muhafaza edilmez, etkin tip *p2
girişimleri kullanmak geçici pointer tipi ve kod olacak *p2
geçici-işaretçi eşleşmedi herhangi türü olarak type Tanımsız Davranışı çağırır. Bir derleyicinin böyle bir şeyi fark edeceğinden son derece düşüktür, ancak modern derleyici felsefesi programcıların Tanımlanmamış Davranışlardan kaçınmasını gerektirdiğinden, tahsis edilmiş depolama alanı kullanmadan yukarıdaki kodu yazmanın başka güvenli yollarını düşünemiyorum. .