Bu, Ubuntu Online, Fedora Online, Windows çevrimiçi emülatörü veya MAC OS çevrimiçi emülatörü gibi birden fazla ücretsiz çevrimiçi iş istasyonumuzdan birini kullanarak OnWorks ücretsiz barındırma sağlayıcısında çalıştırılabilen komut perlgutlarıdır.
Program:
ADI
perlguts - Perl API'sine Giriş
AÇIKLAMA
Bu belge, Perl API'sinin nasıl kullanılacağını açıklamanın yanı sıra bazı bilgiler sağlamaya çalışır.
Perl çekirdeğinin temel işleyişi hakkında bilgi. Tam olmaktan uzak ve muhtemelen
birçok hata içerir. Lütfen herhangi bir soru veya yorumunuzu aşağıdaki yazara yönlendirin.
Değişkenler
Veri tipleri
Perl, Perl'in üç ana veri türünü işleyen üç typedef'e sahiptir:
SV Skaler Değeri
AV Dizi Değeri
HV Hash Değeri
Her typedef, çeşitli veri türlerini yöneten belirli rutinlere sahiptir.
Ne is an "IV"?
Perl, basit bir işaretli tamsayı türü olan özel bir typedef IV kullanır.
bir işaretçiyi (ve bir tamsayıyı) tutacak kadar büyük olmalıdır. Ek olarak, UV,
bu sadece imzasız bir IV.
Perl ayrıca her zaman en az 32 bit olacak olan I16 ve I32 olmak üzere iki özel typedef kullanır.
ve sırasıyla 16 bit uzunluğundadır. (Yine U32 ve U16 da var.)
genellikle tam olarak 32 ve 16 bit uzunluğundadır, ancak Crays'de ikisi de 64 bit olacaktır.
Çalışma ile adet SV
Tek bir komutla bir SV oluşturulabilir ve yüklenebilir. Beş tür değer vardır:
yüklenecek: bir tamsayı değeri (IV), bir işaretsiz tamsayı değeri (UV), bir çift (NV), bir dize
(PV) ve başka bir skaler (SV). ("PV", "İşaret Değeri" anlamına gelir.
yalnızca dizgilere işaret ettiği için yanlış adlandırılmıştır. Ancak, mümkün
başka şeylere işaret etmesi için. Örneğin, bir dizi UV'ye işaret edebilir. Fakat,
dizgeler için olmayanlar için kullanmak, çoğu şeyin altında yatan varsayım olarak, özen gerektirir.
internals, PV'lerin sadece diziler için olmasıdır. Genellikle, örneğin, sondaki bir "NUL"
otomatik olarak takılır. Dize dışı kullanım yalnızca bu paragrafta belgelenmiştir.)
Yedi rutin şunlardır:
SV* yeniSViv(IV);
SV* yeniSVuv(UV);
SV* yeniSVnv(çift);
SV* newSVpv(const char*, STRLEN);
SV* newSVpvn(const char*, STRLEN);
SV* newSVpvf(const karakter*, ...);
SV* yeniSVsv(SV*);
"STRLEN" bir tamsayı türüdür (Size_t, genellikle yapılandırma.h) garantili
perl'in işleyebileceği herhangi bir dizgenin boyutunu temsil edecek kadar büyük olmalıdır.
Daha karmaşık başlatma gerektiren olası olmayan bir SV durumunda, bir SV oluşturabilirsiniz.
newSV(len) ile boş SV. "len" 0 ise, NULL türünde boş bir SV döndürülür, aksi takdirde bir SV
PV tipi, len + 1 ("NUL" için) ayrılmış, erişilebilir depolama baytlarıyla döndürülür
SvPVX aracılığıyla. Her iki durumda da SV undef değerine sahiptir.
SV *sv = yeniSV(0); /* depolama alanı tahsis edilmedi */
SV *sv = yeniSV(10); /* 10 (+1) bayt başlatılmamış depolama
* tahsisli */
Bir değerini değiştirmek için zaten mevcut SV, sekiz rutin vardır:
geçersiz sv_setiv(SV*, IV);
geçersiz sv_setuv(SV*, UV);
void sv_setnv(SV*, çift);
void sv_setpv(SV*, const karakter*);
void sv_setpvn(SV*, const karakter*, STRLEN)
geçersiz sv_setpvf(SV*, const karakter*, ...);
void sv_vsetpvfn(SV*, const char*, STRLEN, va_list *,
SV **, I32, bool *);
geçersiz sv_setsv(SV*, SV*);
Kullanarak atanacak dizenin uzunluğunu belirtmeyi seçebileceğinize dikkat edin.
"sv_setpvn", "newSVpvn" veya "newSVpv" veya Perl'in uzunluğu şu şekilde hesaplamasına izin verebilirsiniz:
"sv_setpv" kullanarak veya "newSVpv" için ikinci argüman olarak 0 belirterek. uyarılırsın
yine de, bu Perl dizenin uzunluğunu "strlen" kullanarak belirleyecektir.
"NUL" karakteriyle biten ve başka şekilde NUL içermeyen dize.
"sv_setpvf" argümanları "sprintf" gibi işlenir ve biçimlendirilmiş çıktı
değer olur.
"sv_vsetpvfn", "vsprintf"in bir analogudur, ancak bir işaretçi belirtmenize izin verir.
değişken bir argüman listesine veya bir dizi SV'nin adresi ve uzunluğuna. Son
argüman bir boole işaret eder; dönüşte, bu boole değeri doğruysa, yerel ayara özgü
bilgi dizgiyi biçimlendirmek için kullanılmıştır ve bu nedenle dizgenin içeriği
güvenilmez (bkz. perlsec). Bu bilgi değilse, bu işaretçi NULL olabilir.
önemli. Bu işlevin, formatın uzunluğunu belirtmenizi gerektirdiğini unutmayın.
"sv_set*()" işlevleri, "büyü" içeren değerler üzerinde çalışacak kadar genel değildir.
Bu belgede daha sonra yer alan "Sihirli Sanal Tablolar" konusuna bakın.
Dizeler içeren tüm SV'ler "NUL" karakteriyle sonlandırılmalıdır. Ya değilse
"NUL" ile sonlandırıldı, kodu geçen çekirdek dökümleri ve bozulma riski vardır.
"NUL" ile sonlandırılmış bir dize bekleyen C işlevlerine veya sistem çağrılarına dize. Perl'in kendi
işlevler bu nedenle tipik olarak sonuna bir "NUL" ekler. Yine de, olmalısın
SV'de saklanan bir dizeyi bir C işlevine veya sistem çağrısına ilettiğinizde çok dikkatli olun.
Bir SV'nin işaret ettiği gerçek değere erişmek için makroları kullanabilirsiniz:
SvIV(SV*)
SvUV(SV*)
SvNV(SV*)
SvPV(SV*, STRLEN uzun)
SvPV_nolen(SV*)
gerçek skaler türü otomatik olarak IV, UV, çift veya dizeye zorlar.
"SvPV" makrosunda, döndürülen dizenin uzunluğu "len" değişkenine yerleştirilir.
(bu bir makro, yani değil &len'i kullanın). Verilerin uzunluğunu umursamıyorsanız
ise, "SvPV_nolen" makrosunu kullanın. Tarihsel olarak global değişkenli "SvPV" makrosu
Bu durumda "PL_na" kullanılmıştır. Ama bu oldukça verimsiz olabilir çünkü "PL_na"
iş parçacıklı Perl'de iş parçacığı yerel deposunda erişilmelidir. Her durumda, bunu hatırla
Perl, hem NUL'ler içerebilen hem de olmayabilen rastgele veri dizilerine izin verir.
"NUL" ile sonlandırılır.
Ayrıca C'nin güvenle "foo(SvPV(s, len), len);" demenize izin vermediğini unutmayın. Olabilir
derleyicinizle çalışın, ancak herkes için çalışmayacak. Bu tür bir ifadeyi kırın
ayrı görevlere:
SV *ler;
STRLEN len;
char * ptr;
ptr = SvPV(ler, uzunluk);
foo(ptr, uzunluk);
Skaler değerin DOĞRU olup olmadığını bilmek istiyorsanız, şunları kullanabilirsiniz:
SvDOĞRU(SV*)
Perl dizeleri sizin için otomatik olarak büyütecek olsa da, eğer Perl'i
SV'niz için daha fazla bellek ayırın, makroyu kullanabilirsiniz
SvGROW(SV*, STRLEN yenilen)
bu, daha fazla bellek ayrılması gerekip gerekmediğini belirleyecektir. Eğer öyleyse, arayacak
"sv_grow" işlevi. "SvGROW" un tahsis edilen miktarı azaltamayacağını, yalnızca artırabileceğini unutmayın.
bir SV'nin belleği ve sondaki "NUL" baytı için otomatik olarak boşluk eklememesi
(Perl'in kendi dize işlevleri genellikle "SvGROW(sv, len + 1)" yapar).
Mevcut bir SV'nin arabelleğine yazmak ve değerini bir dizeye ayarlamak istiyorsanız, şunu kullanın:
SvPV_force() veya SV'yi bir PV olmaya zorlamak için varyantlarından biri. Bu herhangi birini kaldıracak
SV'nin içeriğini korurken SV'den çeşitli türlerde katı olmayan
PV. Bu, örneğin bir API işlevinden bir arabelleğe veri eklemek için kullanılabilir.
fazladan kopyalama olmadan:
(geçersiz)SvPVbyte_force(sv, len);
s = SvGROW(sv, uzun + iğne + 1);
/* s+len'de iğne bayta kadar değişen bir şey, ama
newlen baytları değiştirir
Örneğin. newlen = oku(fd, s + uzun, iğne);
bu örnekler için hataları göz ardı etmek
*/
s[len + newlen] = '\0';
SvCUR_set(sv, uzun + yeni);
SvUTF8_off(sv);
SvSETMAGIC(sv);
Verileriniz zaten hafızadaysa veya kodunuzu basit tutmak istiyorsanız, şunları yapabilirsiniz:
sv_cat*() türevlerinden birini kullanın, örneğin sv_catpvn(). Herhangi bir yere eklemek istiyorsanız
kullanabileceğiniz dize sv_insert() or sv_insert_flags().
SV'nin mevcut içeriğine ihtiyacınız yoksa, aşağıdakilerle bazı kopyalamalardan kaçınabilirsiniz:
sv_setpvn(sv, "", 0);
s = SvGROW(sv, iğneli + 1);
/* s'de iğne bayta kadar değişen, ancak değiştiren bir şey
yeni bayt
Örneğin. newlen = oku(fd, s.iğne);
*/
s[yeni] = '\0';
SvCUR_set(sv, yenilen);
SvPOK_only(sv); /* ayrıca SVf_UTF8'i de temizler */
SvSETMAGIC(sv);
Yine, verileriniz zaten bellekteyse veya verilerin karmaşıklığından kaçınmak istiyorsanız,
yukarıda, kullanabilirsiniz sv_setpvn().
İle ayrılmış bir arabelleğiniz varsa Yenix() ve bunu SV'nin değeri olarak ayarlamak istiyorsanız,
kullanım sv_usepvn_flags(). Perl'in yeniden tahsis edilmesini önlemek istiyorsanız, bunun bazı gereksinimleri vardır.
sondaki NUL'a uyacak arabellek:
Newx(tampon, bir boyut+1, karakter);
/* ... buf'u doldurun ... */
buf[bir boyut] = '\0';
sv_usepvn_flags(sv, buf, bazı boyut, SV_SMAGIC | SV_HAS_TRAILING_NUL);
/* buf artık Perl'e ait, serbest bırakmayın */
Bir SV'niz varsa ve Perl'in içinde ne tür verilerin depolandığını düşündüğünü bilmek istiyorsanız, şunları yapabilirsiniz:
sahip olduğunuz SV türünü kontrol etmek için aşağıdaki makroları kullanın.
SvIOK(SV*)
SvNOK(SV*)
SvPOK(SV*)
Bir SV'de depolanan dizenin geçerli uzunluğunu aşağıdakilerle alabilir ve ayarlayabilirsiniz.
makrolar:
SvCUR(SV*)
SvCUR_set(SV*, I32 değeri)
Makroyla birlikte SV'de depolanan dizenin sonuna bir işaretçi de alabilirsiniz:
SvEND(SV*)
Ancak bu son üç makronun yalnızca "SvPOK()" doğruysa geçerli olduğunu unutmayın.
Bir "SV*" içinde saklanan dizenin sonuna bir şey eklemek istiyorsanız,
aşağıdaki işlevler:
void sv_catpv(SV*, const karakter*);
void sv_catpvn(SV*, const karakter*, STRLEN);
geçersiz sv_catpvf(SV*, const karakter*, ...);
void sv_vcatpvfn(SV*, const char*, STRLEN, va_list *, SV **,
I32, bol);
geçersiz sv_catsv(SV*, SV*);
İlk işlev, "strlen" kullanarak eklenecek dizenin uzunluğunu hesaplar.
İkincisinde, dizenin uzunluğunu kendiniz belirlersiniz. üçüncü fonksiyon
argümanlarını "sprintf" gibi işler ve biçimlendirilmiş çıktıyı ekler. Dördüncü
işlev "vsprintf" gibi çalışır. Bir dizi SV'nin adresini ve uzunluğunu belirtebilirsiniz
va_list argümanı yerine. Beşinci işlev, içinde depolanan dizeyi genişletir.
ikinci SV'de depolanan dize ile ilk SV. Ayrıca ikinci SV'yi olmaya zorlar.
dize olarak yorumlanır.
"sv_cat*()" işlevleri, "büyü" içeren değerler üzerinde çalışacak kadar genel değildir.
Bu belgede daha sonra yer alan "Sihirli Sanal Tablolar" konusuna bakın.
Bir skaler değişkenin adını biliyorsanız, aşağıdakileri kullanarak SV'sine bir işaretçi alabilirsiniz.
Aşağıdaki:
SV* get_sv("package::varname", 0);
Değişken yoksa bu NULL döndürür.
Bu değişkenin (veya başka bir SV'nin) gerçekten "tanımlı" olup olmadığını bilmek istiyorsanız,
telefon etmek:
SvOK(SV*)
Skaler "undef" değeri, "PL_sv_undef" adlı bir SV örneğinde depolanır.
Adresi, bir "SV*" gerektiğinde kullanılabilir. denemediğinizden emin olun
rastgele bir sv'yi &PL_sv_undef ile karşılaştırın. Örneğin, Perl koduyla arayüz oluştururken işe yarayacaktır.
için doğru:
foo(undef);
Ancak şu şekilde çağrıldığında çalışmaz:
$x = tanımsız;
foo($x);
Yani tekrarlamak için her zaman kullanın SvOK() bir sv tanımlı olup olmadığını kontrol etmek için.
Ayrıca &PL_sv_undef'i AV'lerde veya HV'lerde bir değer olarak kullanırken dikkatli olmalısınız (bkz. "AV'ler,
HV'ler ve tanımsız değerler").
Boole değeri DOĞRU ve
FALSE değerleri sırasıyla. "PL_sv_undef" gibi, adresleri herhangi bir
"SV*" gereklidir.
"(SV *) 0"ın &PL_sv_undef ile aynı olduğunu düşünerek aldanmayın. Bunu al
Kod:
SV* sv = (SV*) 0;
if (gerçek-değer-döndürmek için-im) {
sv = sv_2ölümlü(yeniSViv(42));
}
sv_setsv(ST(0), sv);
Bu kod, bir değer döndürmesi gerekiyorsa yeni bir SV (42 değerini içeren) döndürmeye çalışır.
gerçek değer veya başka türlü undef. Bunun yerine, bir yerde bir NULL işaretçisi döndürdü.
hatta, bir segmentasyon ihlaline, veri yolu hatasına veya sadece garip sonuçlara neden olur.
İlk satırda sıfırı &PL_sv_undef olarak değiştirin, her şey yoluna girecek.
Oluşturduğunuz bir SV'yi serbest bırakmak için "SvREFCNT_dec(SV*)" öğesini çağırın. Normalde bu çağrı
gerekli (bkz. "Referans Sayıları ve Mortalite").
Kaydırmaları
Perl, karakterleri en baştan verimli bir şekilde kaldırmak için "sv_chop" işlevini sağlar
bir dizinin; ona bir SV ve PV içinde bir yere bir işaretçi verirsiniz ve atar
işaretçiden önce her şey. Verimlilik, küçük bir hack yoluyla gelir:
aslında karakterleri kaldırarak, "sv_chop", "OOK" (offset OK) bayrağını işaret edecek şekilde ayarlar.
ofset hack'in yürürlükte olduğu diğer işlevler ve PV işaretçisini hareket ettirir (olarak adlandırılır).
"SvPVX"), kesilen bayt sayısı kadar ileri alır ve "SvCUR" ve "SvLEN"i ayarlar
buna göre. (Eski ve yeni PV işaretçileri arasındaki boşluğun bir kısmı depolamak için kullanılır.
doğranmış bayt sayısı.)
Dolayısıyla, bu noktada, tahsis ettiğimiz arabelleğin başlangıcı "SvPVX(sv) -
SvIV(sv)" bellekte ve PV işaretçisi bu tahsis edilenin ortasına işaret ediyor
depolama.
Bu en iyi örnekle gösterilir. Normalde yazma üzerine kopyalama,
operatörün bu hack'i kullanmasını değiştirme, ancak bunun için bir dize oluşturabilirseniz
Yazma üzerine kopyalama mümkün değildir, oyunda görebilirsiniz. Mevcut uygulamada,
bir dize arabelleğinin son baytı, yazma üzerine kopyalama referans sayısı olarak kullanılır. tampon ise
yeterince büyük değilse, yazma üzerine kopyalama atlanır. İlk önce boş bir dizeye bir göz atın:
% ./perl -Ilib -MDevel::Peek -le '$a=""; $a.= ""; $a'yı boşalt
SV = PV(0x7ffb7c008a70) at 0x7ffb7c030390
REFCNT = 1
BAYRAKLAR = (POK,pPOK)
PV = 0x7ffb7bc05b50 ""\0
KÜ = 0
UZUNLUK = 10
Burada LEN'nin 10 olduğuna dikkat edin. (Platformunuza göre farklılık gösterebilir.)
10'dan küçük bir dize ve bir ikame yapın:
% ./perl -Ilib -MDevel::Peek -le '$a=""; $a.="123456789"; $a=~s/.//; Boşalt($a)'
SV = PV(0x7ffa04008a70) at 0x7ffa04030390
REFCNT = 1
BAYRAKLAR = (POK,OOK,pPOK)
OFSET = 1
PV = 0x7ffa03c05b61 ( "\1" . ) "23456789"\0
KÜ = 8
UZUNLUK = 9
Burada kesilen bayt sayısı (1), OFFSET olarak gösterilir. kısmı
"gerçek" ve "sahte" başlangıçlar arasındaki dize parantez içinde gösterilir ve
"SvCUR" ve "SvLEN" değerleri gerçek olanı değil, sahte başlangıcı yansıtır. (İlk
dize arabelleğinin karakteri burada "1" değil, "\1" olarak değişmiştir, çünkü
mevcut uygulama, ofset sayısını dize arabelleğinde saklar. Bu tabidir
değiştirmek.)
Verimli geçişi sağlamak için AV'lerde ofset hack'e benzer bir şey gerçekleştirilir ve
dizinin başlangıcının eklenmesi; "AvARRAY", içindeki ilk öğeye işaret ederken
Perl'den görünen dizi, "AvALLOC", C dizisinin gerçek başlangıcına işaret eder.
Bunlar genellikle aynıdır, ancak artırılarak bir "vardiya" işlemi yapılabilir.
"AvARRAY" birer birer ve "AvFILL" ve "AvMAX" azalıyor. Yine, gerçek konumu
C dizisinin başlangıcı yalnızca dizi serbest bırakıldığında devreye girer. "av_shift" bölümüne bakın Av.c.
Neler bulunuyor Gerçekten Saklanan in an SV mi?
Sahip olduğunuz skaler tipini belirlemenin genel yönteminin "Sv*OK" kullanmak olduğunu hatırlayın.
makrolar. Bir skaler hem sayı hem de dize olabileceğinden, genellikle bu makrolar
her zaman DOĞRU döndür ve "Sv*V" makrolarını çağırmak, uygun dönüştürme işlemini yapacaktır.
dizeden tamsayıya/çiftten veya tamsayıdan/çiftten dizeye.
Eğer sen Gerçekten mi bir SV'de tamsayı, çift veya dize işaretçiniz olup olmadığını bilmeniz gerekir.
bunun yerine aşağıdaki üç makroyu kullanabilir:
SvIOKp(SV*)
SvNOKp(SV*)
SvPOKp(SV*)
Bunlar, dosyanızda gerçekten bir tamsayı, çift veya dize işaretçiniz olup olmadığını size söyleyecektir.
SV. "p" özel anlamına gelir.
Özel ve genel bayrakların farklı olabileceği çeşitli yollar vardır. örneğin,
perl 5.16 ve önceki sürümlerde, berabere kalan bir SV, IV yuvasında geçerli bir temel değere sahip olabilir (yani
SvIOKp doğrudur), ancak verilere FETCH rutini yerine FETCH rutini aracılığıyla erişilmelidir.
doğrudan, bu nedenle SvIOK yanlıştır. (Perl 5.18'den itibaren, bağlı skaler bayrakları aynı
çözülmemiş skaler gibi.) Bir diğeri, sayısal dönüşümün gerçekleştiği ve kesinliğin olduğu zamandır.
kayıp: 'kayıplı' değerlerde yalnızca özel bayrak ayarlanır. Yani bir NV dönüştürüldüğünde
kayıplı bir IV, SvIOKp, SvNOKp ve SvNOK ayarlanacak, SvIOK olmayacak.
Genel olarak, yine de "Sv*V" makrolarını kullanmak en iyisidir.
Çalışma ile AV'ler
AV oluşturmanın ve yüklemenin iki yolu vardır. İlk yöntem boş bir AV oluşturur:
AV* yeniAV();
İkinci yöntem hem AV'yi oluşturur hem de başlangıçta onu SV'lerle doldurur:
AV* av_make(SSize_t sayi, SV **ptr);
İkinci argüman, "num" "SV*"'leri içeren bir diziye işaret eder. AV bir kez
oluşturulduğunda, istenirse SV'ler yok edilebilir.
AV oluşturulduktan sonra, üzerinde aşağıdaki işlemler mümkündür:
geçersiz av_push(AV*, SV*);
SV* av_pop(AV*);
SV* av_shift(AV*);
void av_unshift(AV*, SSize_t say);
Bunlar, "av_unshift" dışında tanıdık işlemler olmalıdır. Bu rutin
"undef" değeriyle dizinin önüne "num" öğelerini ekler. o zaman kullanmalısın
Bu yeni öğelere değerler atamak için "av_store" (aşağıda açıklanmıştır).
İşte diğer bazı işlevler:
SSize_t av_top_index(AV*);
SV** av_fetch(AV*, SSize_t anahtarı, I32 lval);
SV** av_store(AV*, SSize_t anahtarı, SV* değeri);
"av_top_index" işlevi, bir dizideki en yüksek dizin değerini döndürür (tıpkı $#array gibi
Perl'de). Dizi boşsa, -1 döndürülür. "av_fetch" işlevi,
"anahtar" dizinindeki değer, ancak "lval" sıfır değilse, "av_fetch" bir undef değeri depolayacaktır
o indekste. "av_store" işlevi, "val" değerini "anahtar" dizininde saklar ve
"val" referans sayısını artırmaz. Böylece arayan kişi almaktan sorumludur.
bununla ilgilenin ve "av_store" NULL değerini döndürürse, arayan kişinin
bellek sızıntısını önlemek için referans sayısı. "av_fetch" ve "av_store" öğelerinin her ikisinin de geri döndüğünü unutmayın
Dönüş değeri olarak "SV*" değil, "SV**"'ler.
Biraz daha:
geçersiz av_clear(AV*);
geçersiz av_undef(AV*);
void av_extend(AV*, SSize_t anahtarı);
"av_clear" işlevi, AV* dizisindeki tüm öğeleri siler, ancak gerçekte
dizinin kendisini silin. "av_undef" işlevi, içindeki tüm öğeleri siler.
dizi artı dizinin kendisi. "av_extend" işlevi, diziyi genişletecek şekilde genişletir.
en az "anahtar+1" öğeleri içerir. "Anahtar+1" şu anda tahsis edilenden küçükse
dizinin uzunluğu, sonra hiçbir şey yapılmaz.
Bir dizi değişkeninin adını biliyorsanız, aşağıdakileri kullanarak AV'sine bir işaretçi alabilirsiniz.
Aşağıdaki:
AV* get_av("package::varname", 0);
Değişken yoksa bu NULL döndürür.
Nasıl kullanılacağı hakkında daha fazla bilgi için "Bağlı Hashlerin ve Dizilerin Sihrini Anlamak" bölümüne bakın.
bağlı dizilerde dizi erişim işlevleri.
Çalışma ile HV'ler
Bir HV oluşturmak için aşağıdaki rutini kullanırsınız:
YG* yeniHV();
HV oluşturulduktan sonra, üzerinde aşağıdaki işlemler mümkündür:
SV** hv_store(HV*, const char* anahtarı, U32 klen, SV* val, U32 hash);
SV** hv_fetch(HV*, const char* anahtarı, U32 klen, I32 lval);
"Klen" parametresi, geçirilen anahtarın uzunluğudur (0'ı geçemeyeceğinizi unutmayın.
Perl'e anahtarın uzunluğunu ölçmesini söylemek için "klen" değeri olarak). "val"
argüman, saklanan skalere yönelik SV işaretçisini içerir ve "karma" önceden hesaplanmış
hash değeri ("hv_store" un sizin için hesaplamasını istiyorsanız sıfır). "lval" parametresi
bu getirmenin aslında bir mağaza işleminin parçası olup olmadığını gösterir, bu durumda yeni bir
verilen anahtarla HV'ye tanımsız değer eklenecek ve "hv_fetch" geri dönecek
sanki değer zaten varmış gibi.
"hv_store" ve "hv_fetch" öğelerinin yalnızca "SV*" değil, "SV**" döndürdüğünü unutmayın. erişmek için
skaler değer, önce dönüş değerinin referansını kaldırmanız gerekir. Ancak, kontrol etmelisiniz
referansını kaldırmadan önce dönüş değerinin NULL olmadığından emin olun.
Bu iki işlevden ilki, bir karma tablo girişinin olup olmadığını kontrol eder ve ikincisi
siler.
bool hv_exists(HV*, const char* anahtarı, U32 klen);
SV* hv_delete(HV*, const char* anahtarı, U32 klen, I32 bayrakları);
"flags", "G_DISCARD" bayrağını içermiyorsa, "hv_delete" bir
silinen değerin ölümlü kopyası.
Ve daha çeşitli işlevler:
geçersiz hv_clear(HV*);
geçersiz hv_undef(HV*);
AV benzerleri gibi, "hv_clear" da karma tablosundaki tüm girdileri siler ancak
aslında karma tablosunu silmeyin. "hv_undef" hem girdileri hem de hash'i siler
tablonun kendisi.
Perl, gerçek verileri HE typedef ile bağlantılı bir yapılar listesinde tutar. Bunlar
gerçek anahtar ve değer işaretçilerini içerir (artı ek yönetim yükü). Anahtar
bir dize işaretçisidir; değer bir "SV*" dir. Ancak, bir "HE*" elde ettiğinizde,
gerçek anahtar ve değer, aşağıda belirtilen rutinleri kullanın.
I32 hv_iterinit(HV*);
/* Hash tablosunu dolaşmak için başlangıç noktasını hazırlar */
HE* hv_iternext(HV*);
/* Bir sonraki girişi alın ve bir işaretçiyi bir
hem anahtara hem de değere sahip yapı */
char* hv_iterkey(HE* girişi, I32* retlen);
/* HE yapısından anahtarı al ve geri dön
anahtar dizesinin uzunluğu */
SV* hv_iterval(HV*, HE* girişi);
/* HE değerine bir SV işaretçisi döndür
yapı */
SV* hv_iternextsv(HV*, karakter** anahtarı, I32* yeniden verildi);
/* Bu kolaylık rutini hv_iternext'i birleştirir,
hv_iterkey ve hv_iterval. Anahtar ve retlen
argümanlar, anahtarın dönüş değerleridir ve
uzunluk. Değer, SV* bağımsız değişkeninde döndürülür */
Bir karma değişkenin adını biliyorsanız, aşağıdakileri kullanarak HV'sine bir işaretçi alabilirsiniz.
Aşağıdaki:
HV* get_hv("paket::varname", 0);
Değişken yoksa bu NULL döndürür.
Hash algoritması "PERL_HASH" makrosunda tanımlanmıştır:
PERL_HASH(karma, anahtar, klen)
Bu makronun tam olarak uygulanması, Perl'in mimarisine ve sürümüne göre değişir ve
dönüş değeri çağrı başına değişebilir, bu nedenle değer yalnızca bir
tek perl işlemi.
Nasıl kullanılacağı hakkında daha fazla bilgi için "Bağlı Hashlerin ve Dizilerin Sihrini Anlamak" bölümüne bakın.
bağlı karmalarda karma erişim işlevleri.
Esrar API uzantıları
5.004 sürümünden itibaren aşağıdaki işlevler de desteklenmektedir:
HE* hv_fetch_ent (HV* tb, SV* anahtarı, I32 lval, U32 karma);
HE* hv_store_ent (HV* tb, SV* anahtarı, SV* değeri, U32 karma);
bool hv_exists_ent (HV* tb, SV* anahtarı, U32 karma);
SV* hv_delete_ent (HV* tb, SV* anahtarı, I32 bayrakları, U32 karma);
SV* hv_iterkeysv (HE* girişi);
Bu işlevlerin, uzantı kodunun yazılmasını kolaylaştıran "SV*" tuşlarını aldığını unutmayın.
karma yapılarla ilgilenir. Bu işlevler ayrıca "SV*" tuşlarının "tie" için geçirilmesine de izin verir.
sizi tuşları dizmeye zorlamadan çalışır (önceki
fonksiyonlar).
Ayrıca tüm hash girişlerini ("HE*") döndürür ve kabul ederler, bu da kullanımlarını daha verimli hale getirir.
(belirli bir dizgenin karma numarasının her seferinde yeniden hesaplanması gerekmediğinden).
Ayrıntılı açıklamalar için perlapi'ye bakın.
Hash girdilerinin içeriğine erişmek için her zaman aşağıdaki makrolar kullanılmalıdır. Not
Bu makroların argümanları, değerlendirilebilecekleri için basit değişkenler olmalıdır.
birden fazla. Bu makroların ayrıntılı açıklamaları için bkz.
HePV(HE* o, STRLEN len)
HeVAL(HE* o)
HeHASH(HE* o)
HeSVKEY(HE* o)
HeSVKEY_force(HE* o)
HeSVKEY_set(HE* o, SV* sv)
Bu iki alt seviye makro tanımlanmıştır, ancak yalnızca tuşlarla uğraşırken kullanılmalıdır.
"SV*" olmayanlar:
heKEY(HE* o)
HeKLEN(HE* o)
Hem "hv_store" hem de "hv_store_ent" öğesinin referans sayısını artırmadığını unutmayın.
arayanın sorumluluğunda olan kayıtlı "val". Bu işlevler bir NULL döndürürse
değer, arayan genellikle bir önlemek için "val" referans sayısını azaltmak zorunda kalacaktır.
bellek sızıntısı.
AV'ler, HV'ler ve tanımlanmamış değerlerimiz
Bazen tanımsız değerleri AV'lerde veya HV'lerde saklamanız gerekir. Bu nadir de olsa
durumda, zor olabilir. Bunun nedeni, ihtiyacınız olduğunda &PL_sv_undef kullanmaya alışmış olmanızdır.
tanımsız SV.
Örneğin, sezgi size bu XS kodunun:
AV *av = yeniAV();
av_store( av, 0, &PL_sv_undef);
bu Perl koduna eşdeğerdir:
@av'm;
$av[0] = tanımsız;
Ne yazık ki, bu doğru değil. Perl 5.18 ve önceki sürümlerde, AV'ler &PL_sv_undef'i bir
bir dizi öğesinin henüz başlatılmadığını gösteren işaretçi. Böylece "var
$av[0]", yukarıdaki Perl kodu için doğru olur, ancak XS tarafından oluşturulan dizi için yanlış olur.
kod. Perl 5.20'de &PL_sv_undef'i depolamak salt okunur bir öğe yaratacaktır, çünkü
skaler &PL_sv_undef kopyası değil, kendisi saklanır.
&PL_sv_undef'i HV'lerde depolarken benzer sorunlar ortaya çıkabilir:
hv_store(hv, "anahtar", 3, &PL_sv_undef, 0 );
Bu gerçekten "undef" değerini yapacaktır, ancak "key" değerini değiştirmeye çalışırsanız,
aşağıdaki hatayı alırsınız:
Oluşturulamayan karma değerin değiştirilmesi denendi
Perl 5.8.0'da &PL_sv_undef, kısıtlı karmalarda yer tutucuları işaretlemek için de kullanıldı. Bu
hash üzerinde yineleme yapılırken veya kontrol edilirken bu tür hash girişlerinin görünmemesine neden oldu.
"hv_exists" işlevine sahip tuşlar.
&PL_sv_yes veya &PL_sv_no'yu AV'lere veya HV'lere kaydettiğinizde benzer sorunlarla karşılaşabilirsiniz.
Bu tür öğeleri değiştirmeye çalışmak size aşağıdaki hatayı verecektir:
Salt okunur bir değerin değiştirilmesi denendi
Uzun lafın kısası, &PL_sv_undef, &PL_sv_yes ve özel değişkenleri kullanabilirsiniz.
AV'ler ve HV'ler ile &PL_sv_no, ancak ne yaptığınızı bildiğinizden emin olmalısınız.
Genel olarak, bir AV veya HV'de tanımsız bir değer depolamak istiyorsanız, kullanmamalısınız.
&PL_sv_undef, bunun yerine "newSV" işlevini kullanarak yeni bir tanımsız değer oluşturun,
örnek:
av_store( ortalama, 42, yeniSV(0));
hv_store(hv, "foo", 3, yeniSV(0), 0);
Referanslar
Referanslar, diğer veri türlerine (diğer veri türleri dahil) işaret eden özel bir skaler türüdür.
Referanslar).
Referans oluşturmak için aşağıdaki işlevlerden birini kullanın:
SV* newRV_inc((SV*) olayı);
SV* newRV_noinc((SV*) olayı);
"Şey" argümanı bir "SV*", "AV*" veya "HV*" olabilir. Fonksiyonlar aynı
"newRV_inc", "şeyin" referans sayısını artırırken, "newRV_noinc"
değil. Tarihsel nedenlerden dolayı "newRV", "newRV_inc" ile eşanlamlıdır.
Bir referansınız olduğunda, referansın referansını kaldırmak için aşağıdaki makroyu kullanabilirsiniz:
SvRV(SV*)
sonra uygun rutinleri çağırın, döndürülen "SV*" yi bir "AV*" veya
"HV*", gerekirse.
Bir SV'nin referans olup olmadığını belirlemek için aşağıdaki makroyu kullanabilirsiniz:
SvROK(SV*)
Referansın ne tür bir değere atıfta bulunduğunu keşfetmek için aşağıdaki makroyu kullanın ve ardından
dönüş değerini kontrol edin.
SvTİP(SvRV(SV*))
Döndürülecek en kullanışlı türler şunlardır:
< SVt_PVAV Skaler
SVt_PVAV Dizisi
SVt_PVHV Karması
SVt_PVCV Kodu
SVt_PVGV Glob (muhtemelen bir dosya tanıtıcısı)
Daha fazla ayrıntı için perlapi'de "svtype" bölümüne bakın.
Mübarek Referanslar ve Sınıf nesneler
Referanslar ayrıca nesne yönelimli programlamayı desteklemek için kullanılır. Perl'in OO sözlüğünde, bir
nesne, yalnızca bir pakete (veya sınıfa) kutsanmış bir referanstır. Bir kere
kutsanmış, programcı şimdi referansı, içindeki çeşitli yöntemlere erişmek için kullanabilir.
sınıf.
Bir referans, aşağıdaki işleve sahip bir pakete kutsanabilir:
SV* sv_bless(SV* sv, HV* saklama);
"sv" bağımsız değişkeni bir başvuru değeri olmalıdır. "Stash" argümanı hangi sınıfın
referansa ait olacaktır. Sınıf dönüştürme hakkında bilgi için "Zebalar ve Küreler"e bakın
isimler zulalara.
/* Hala inşaat halinde */
Aşağıdaki işlev, halihazırda bir tane değilse, rv'yi referans olacak şekilde yükseltir. için yeni bir SV oluşturur
rv işaret etmek için. "Sınıf adı" boş değilse, SV belirtilen sınıfa kutsanır.
SV döndürülür.
SV* newSVrv(SV* rv, const char* sınıf adı);
Aşağıdaki üç işlev, tamsayıyı, işaretsiz tamsayıyı veya iki katı olan bir SV'ye kopyalar.
referans "rv" dir. "Sınıf adı" boş değilse SV kutsanmıştır.
SV* sv_setref_iv(SV* rv, const char* sınıf adı, IV iv);
SV* sv_setref_uv(SV* rv, const char* sınıf adı, UV uv);
SV* sv_setref_nv(SV* rv, const char* sınıf adı, NV iv);
Aşağıdaki işlev, işaretçi değerini kopyalar (the adres, değil the sicim!) bir SV'ye
referansı rv olan. "Sınıf adı" boş değilse SV kutsanmıştır.
SV* sv_setref_pv(SV* rv, const char* sınıf adı, geçersiz* pv);
Aşağıdaki işlev, bir dizeyi referansı "rv" olan bir SV'ye kopyalar. Uzunluğu ayarla
0 Perl'in dize uzunluğunu hesaplamasına izin vermek için. "Sınıf adı" boş değilse SV kutsanmıştır.
SV* sv_setref_pvn(SV* rv, const char* sınıf adı, char* pv,
STRLEN uzunluğu);
Aşağıdaki işlev, SV'nin belirtilen sınıfa kutsanmış olup olmadığını test eder. yapar
miras ilişkilerini kontrol etmeyin.
int sv_isa(SV* sv, const karakter* isim);
Aşağıdaki fonksiyon, SV'nin kutsanmış bir nesneye referans olup olmadığını test eder.
int sv_isobject(SV* sv);
Aşağıdaki işlev, SV'nin belirtilen sınıftan türetilip türetilmediğini test eder. SV olabilir
kutsanmış bir nesneye referans veya bir sınıf adı içeren bir dize olabilir. Bu
"EVRENSEL::isa" işlevini uygulayan işlev.
bool sv_derived_from(SV* sv, const karakter* isim);
Belirli bir sınıftan türetilmiş bir nesneniz olup olmadığını kontrol etmek için şunu yazmanız gerekir:
if (sv_isobject(sv) && sv_derived_from(sv, class)) { ... }
Oluşturma Yeni Değişkenler
Perl'inizden erişilebilen undef değerine sahip yeni bir Perl değişkeni oluşturmak için
komut dosyası, değişken türüne bağlı olarak aşağıdaki rutinleri kullanın.
SV* get_sv("package::varname", GV_ADD);
AV* get_av("package::varname", GV_ADD);
HV* get_hv("paket::varname", GV_ADD);
İkinci parametre olarak GV_ADD kullanımına dikkat edin. Yeni değişken şimdi kullanılarak ayarlanabilir.
veri tipine uygun rutinler.
Değerleri "GV_ADD" bağımsız değişkeni ile bit düzeyinde VEYA'lanabilen ek makrolar vardır.
belirli ekstra özellikleri etkinleştirmek için. Bu bitler:
GV_ADDMULTI
Değişkeni çarpma tanımlı olarak işaretler, böylece şunları önler:
İsim yalnızca bir kez kullanıldı: olası yazım hatası
uyarı.
GV_ADDWARN
Şu uyarıyı verir:
oluşturmak zorunda kaldı beklenmedik bir şekilde
değişken, işlev çağrılmadan önce mevcut değilse.
Bir paket adı belirtmezseniz, değişken geçerli pakette oluşturulur.
Referans Sayımlar ve Ölümlülük
Perl, referansa dayalı bir çöp toplama mekanizması kullanır. SV'ler, AV'ler veya HV'ler (xV için
kısa) hayatlarına 1 referans sayısı ile başlarlar.
xV sayısı 0'a düşerse yok edilir ve hafızası kullanılabilir hale gelir
yeniden kullanım için.
Bu normalde, bir değişken tanımlanmamış veya sonuncusu olmadıkça Perl düzeyinde gerçekleşmez.
kendisine bir referans tutan değişken değiştirilir veya üzerine yazılır. İç düzeyde,
ancak, referans sayıları aşağıdaki makrolarla değiştirilebilir:
int SvREFCNT(SV* sv);
SV* SvREFCNT_inc(SV* sv);
geçersiz SvREFCNT_dec(SV* sv);
Ancak, referans sayısını manipüle eden başka bir fonksiyon daha vardır.
argüman. Hatırlayacağınız "newRV_inc" işlevi, belirtilene bir referans oluşturur.
argüman. Bir yan etki olarak, argümanın referans sayısını arttırır. bu değilse
ne istersen, bunun yerine "newRV_noinc" kullan.
Örneğin, bir XSUB işlevinden bir başvuru döndürmek istediğinizi düşünün. İçinde
XSUB rutini, başlangıçta bir referans sayısına sahip bir SV oluşturursunuz. Sonra siz
yeni oluşturulan SV'yi ileterek "newRV_inc" arayın. Bu, referansı yeni bir SV olarak döndürür,
ancak "newRV_inc" e ilettiğiniz SV'nin referans sayısı ikiye çıkarıldı.
Şimdi XSUB rutininden referansı döndürürsünüz ve SV'yi unutursunuz. Ama Perl
yok! Döndürülen referans yok edildiğinde, orijinalin referans sayısı
SV bire düşürülür ve hiçbir şey olmaz. SV herhangi bir şekilde takılmayacak
Perl sona erene kadar ona erişin. Bu bir bellek sızıntısıdır.
O halde doğru prosedür, "newRV_inc" yerine "newRV_noinc" kullanmaktır. Sonra, eğer ve
son referans yok edildiğinde, SV'nin referans sayısı sıfıra gidecek ve
yok edilecek ve herhangi bir bellek sızıntısı durdurulacaktır.
xV'lerin yok edilmesine yardımcı olabilecek bazı kolaylık işlevleri mevcuttur.
Bu işlevler "ölümlülük" kavramını ortaya çıkarır. Ölümlü olan bir xV'nin sahip olduğu
referans sayısı azaltılmak üzere işaretlendi, ancak gerçekte azalmadı, "kısa bir
zaman sonra". Genellikle "kısa süre sonra" terimi, tek bir Perl ifadesi anlamına gelir, örneğin
bir XSUB işlevine yapılan çağrı. Ölümlü xV'lerin sahip oldukları zamanın gerçek belirleyicisi
azalan referans sayısı, SAVETMPS ve FREETMPS olmak üzere iki makroya bağlıdır. Bkz. perlcall
ve bu makrolar hakkında daha fazla ayrıntı için perlxs.
"Ölümlüleştirme" en basit haliyle ertelenmiş bir "SvREFCNT_dec"dir. Ancak, eğer
bir değişkeni iki kez ölümle, referans sayısı daha sonra iki kez azaltılacaktır.
"Ölümlü" SV'ler, çoğunlukla Perl'in yığınına yerleştirilen SV'ler için kullanılır. Örneğin bir SV
sadece çağrılan bir alt numaraya bir sayı iletmek için oluşturulan, temizlenmesi için ölümlü yapılır
yığından çıktığında otomatik olarak açılır. Benzer şekilde, XSUB'lar tarafından döndürülen sonuçlar
(yığın üzerine itilen) genellikle ölümlü yapılır.
Ölümlü bir değişken oluşturmak için şu işlevleri kullanın:
SV* sv_newmortal()
SV* sv_2mortal(SV*)
SV* sv_mortalcopy(SV*)
İlk çağrı ölümlü bir SV (değersiz) oluşturur, ikincisi mevcut bir SV'yi
ölümlü bir SV (ve dolayısıyla "SvREFCNT_dec" çağrısını erteler) ve üçüncüsü bir ölümlü yaratır
mevcut bir SV'nin kopyası. "sv_newmortal" yeni SV'ye değer vermediğinden,
normalde "sv_setpv", "sv_setiv" vb. yoluyla bir tane verilir:
SV *tmp = sv_newmortal();
sv_setiv(tmp, bir_integer);
Bu, birden çok C ifadesi olduğu için oldukça yaygındır, bunun yerine şu deyime bakın:
SV *tmp = sv_2mortal(newSViv(an_integer));
Ölümlü değişkenler oluştururken dikkatli olmalısınız. Garip şeyler olabilir eğer
aynı değeri birden çok bağlamda ölümlü yapın veya bir değişkeni ölümlü yaparsanız
bir kaç sefer. "Ölümlüleştirmeyi" ertelenmiş "SvREFCNT_dec" olarak düşünmek,
Bu tür sorunları en aza indirin. Örneğin, bir SV'yi geçiyorsanız, bilmek yüksek
Yığın üzerinde kullanımından kurtulmak için yeterli REFCNT herhangi bir fanileştirme yapmanıza gerek yoktur. Eğer sen
"SvREFCNT_inc" ve "sv_2mortal" yapmak veya "sv_mortalcopy" yapmak olduğundan emin değilseniz
daha güvenli.
Ölümlü rutinler sadece SV'ler için değildir; AV'ler ve HV'ler geçirilerek ölümlü hale getirilebilir.
"sv_2mortal" veya "sv_mortalcopy" yordamlarına adres ("SV*" olarak türetilmiştir).
miktarlarsa ve Küreler
A saklamak bir paket içinde tanımlanan tüm değişkenleri içeren bir karmadır. Her anahtar
zulanın bir sembol adıdır (buna sahip tüm farklı nesne türleri tarafından paylaşılır).
aynı ad) ve karma tablosundaki her değer bir GV'dir (Glob Value). Bu GV sırayla
dahil (ancak bunlarla sınırlı olmamak üzere) bu ismin çeşitli nesnelerine referanslar içerir
şu:
skaler değer
Dizi Değeri
Hash Değeri
G/Ç Kolu
oluşturulan
Alt program
"Main" de var olan öğeleri tutan "PL_defstash" adında tek bir zula vardır.
paket. Diğer paketlerdeki öğelere ulaşmak için pakete "::" dizesini ekleyin
isim. "Foo" paketindeki öğeler, PL_defstash içindeki "Foo::" zulasındadır. Nesneler
"Bar::Baz" paketindeki "Bar::" deposundaki "Baz::" zulasındadır.
Belirli bir paket için saklama işaretçisini almak için şu işlevi kullanın:
HV* gv_stashpv(const char* adı, I32 bayrakları)
HV* gv_stashsv(SV*, I32 bayrakları)
İlk işlev değişmez bir dize alır, ikincisi SV'de depolanan dizeyi kullanır.
Saklamanın yalnızca bir karma tablo olduğunu unutmayın, bu nedenle bir "HV*" elde edersiniz. "bayraklar" bayrağı
GV_ADD olarak ayarlanmışsa yeni bir paket oluşturacaktır.
"gv_stash*v"nin istediği isim, sembol tablosunu istediğiniz paketin ismidir.
Varsayılan paket "ana" olarak adlandırılır. Birden çok iç içe paketiniz varsa, bunların
Perl dilinde olduğu gibi "::" ile ayrılmış "gv_stash*v" adları.
Alternatif olarak, kutsanmış bir referans olan bir SV'niz varsa, zulayı öğrenebilirsiniz.
kullanarak işaretçi:
YG* SvSTASH(SvRV(SV*));
ardından paket adının kendisini almak için aşağıdakileri kullanın:
char* HvNAME(HV* zula);
Bir nesneyi kutsamanız veya yeniden kutsamanız gerekirse, aşağıdaki işlevi kullanabilirsiniz:
SV* sv_bless(SV*, HV* saklama)
burada ilk argüman, bir "SV*" bir referans olmalı ve ikinci argüman bir
saklamak. Döndürülen "SV*" artık diğer herhangi bir SV ile aynı şekilde kullanılabilir.
Referanslar ve nimetler hakkında daha fazla bilgi için perlref'e danışın.
Çift Yazılı adet SV
Skaler değişkenler normalde yalnızca bir tür değer içerir, bir tamsayı, çift, işaretçi veya
referans. Perl, saklanan türden gerçek skaler verileri otomatik olarak dönüştürür
istenen türe girin.
Bazı skaler değişkenler, birden fazla skaler veri türü içerir. Örneğin,
değişken $! "errno"nun sayısal değerini veya dize eşdeğerini içerir.
"strerror" veya "sys_errlist[]".
Bir SV'ye birden çok veri değerini zorlamak için iki şey yapmanız gerekir: "sv_set*v" kullanın
ek skaler tip eklemek için rutinler, ardından Perl'in inanacağı şekilde bir bayrak ayarlayın
birden fazla veri türü içerir. Bayrakları ayarlamak için dört makro şunlardır:
SvIOK_on
SvNOK_on
SvPOK_on
SvROK_on
Kullanmanız gereken belirli makro, önce hangi "sv_set*v" rutinini aradığınıza bağlıdır.
Bunun nedeni, her "sv_set*v" rutininin yalnızca belirli türdeki biti açmasıdır.
veri ayarlanıyor ve geri kalan her şeyi kapatıyor.
Örneğin, "dberror" adlı yeni bir Perl değişkeni oluşturmak için
ve açıklayıcı dize hata değerleri için aşağıdaki kodu kullanabilirsiniz:
harici int dberror;
harici karakter *dberror_list;
SV* sv = get_sv("dberror", GV_ADD);
sv_setiv(sv, (IV) hata);
sv_setpv(sv, dberror_list[dberror]);
SvIOK_on(sv);
"sv_setiv" ve "sv_setpv" sırası tersine çevrilmişse, "SvPOK_on" makrosu
"SvIOK_on" yerine çağrılması gerekir.
Sadece oku Değerler
Perl 5.16 ve önceki sürümlerde, yazma üzerine kopyalama (sonraki bölüme bakın) ile bir bayrak biti paylaştı.
salt okunur skaler Bu nedenle, "sv_setsv"nin vb. olup olmadığını test etmenin tek yolu bir
Bu sürümlerde "salt okunur bir değerin değiştirilmesi" hatası:
SvREADONLY(sv) && !SvIsCOW(sv)
Perl 5.18 ve sonraki sürümlerde, SvREADONLY yalnızca salt okunur değişkenler için geçerlidir ve
5.20, yazma üzerine kopyalama skalerleri de salt okunur olabilir, bu nedenle yukarıdaki kontrol yanlıştır. Sen
sadece istiyorum:
SvREADONLY(sv)
Bu kontrolü sık sık yapmanız gerekiyorsa, kendi makronuzu şu şekilde tanımlayın:
#if PERL_VERSION >= 18
# SvTRULYREADONLY(sv) SvREADONLY(sv) tanımla
#else
# tanımla SvTRULYREADONLY(sv) (SvREADONLY(sv) && !SvIsCOW(sv))
#endif
kopya on Yazmak
Perl, skalerler için bir yazma üzerine kopyalama (COW) mekanizması uygular;
istendiğinde hemen yapılmaz, ancak biri veya biri tarafından gerekli görülene kadar ertelenir.
diğer skaler değişim. Bu çoğunlukla şeffaftır, ancak değişiklik yapmamaya özen gösterilmelidir.
birden çok SV tarafından paylaşılan dize arabellekleri.
Bir SV'nin "SvIsCOW(sv)" ile yazma üzerine kopyalama kullanıp kullanmadığını test edebilirsiniz.
Bir SV'yi arayarak dize arabelleğinin kendi kopyasını oluşturmaya zorlayabilirsiniz.
"sv_force_normal(sv)" veya SvPV_force_nolen(sv).
SV'nin dize arabelleğini düşürmesini istiyorsanız, "sv_force_normal_flags(sv,
SV_COW_DROP_PV)" veya basitçe "sv_setsv(sv, NULL)".
Bu işlevlerin tümü salt okunur skalerlerde vıraklayacaktır (daha fazla bilgi için önceki bölüme bakın).
bunlarda).
Sistemlerde kodunuzun doğru çalıştığını ve COW arabelleklerini değiştirmediğini test etmek için
bu destek mmap(2) (yani, Unix) ile perl'i yapılandırabilirsiniz
"-Accflags=-DPERL_DEBUG_READONLY_COW" ve arabellek ihlallerini çökmelere dönüştürecektir.
Olağanüstü yavaş olduğunu göreceksiniz, bu yüzden Perl'in kendi testlerini atlamak isteyebilirsiniz.
sihirli Değişkenler
[Bu bölüm hala yapım aşamasındadır. Buradaki her şeyi görmezden gelin. Fatura yok.
İzin verilmeyen her şey yasaktır.]
Herhangi bir SV büyülü olabilir, yani normal bir SV'nin sahip olmadığı özel özelliklere sahiptir.
Bu özellikler, bağlantılı bir "yapı büyüsü" listesinde SV yapısında depolanır,
typedef'ed "MAGIC".
yapı büyüsü {
MAGIC* mg_moremagic;
MGVTBL* mg_sanal;
U16 mg_özel;
char mg_type;
U8 mg_flags;
I32 mg_len;
SV* mg_obj;
karakter* mg_ptr;
};
Bunun yama seviyesi 0'dan itibaren geçerli olduğunu ve herhangi bir zamanda değişebileceğini unutmayın.
atama sihirli
Perl, sv_magic işlevini kullanarak bir SV'ye sihir ekler:
void sv_magic(SV* sv, SV* nesne, int nasıl, const char* isim, I32 isim);
"sv" argümanı, yeni bir sihirli özellik elde edecek olan SV'nin bir göstergesidir.
"sv" zaten sihirli değilse, Perl "sv"yi türe dönüştürmek için "SvUPGRADE" makrosunu kullanır.
"SVt_PVMG". Perl daha sonra bağlantılı listenin başına yeni sihir ekleyerek devam eder.
büyülü özelliklerden. Aynı büyü türünden önceki herhangi bir giriş silinir. Bunu not et
bu geçersiz kılınabilir ve aynı tür sihrin birden çok örneği ilişkilendirilebilir.
bir SV ile.
"name" ve "namlen" argümanları, bir dizeyi sihirle ilişkilendirmek için kullanılır, tipik olarak
bir değişkenin adı. "namlen", "mg_len" alanında saklanır ve "name" değilse
null ise ya "name"nin bir "savepvn" kopyası ya da "name"nin kendisi "mg_ptr" içinde saklanır
alan, "namlen" in sırasıyla sıfırdan büyük veya sıfıra eşit olmasına bağlı olarak.
Özel bir durum olarak, "(name && namlen == HEf_SVKEY)" ise, "name"nin bir
"SV*" ve artan REFCNT ile olduğu gibi saklanır.
sv_magic işlevi, varsa, hangisinin önceden tanımlanmış "Sihirli Sanal" olduğunu belirlemek için "nasıl"ı kullanır.
Tablo", "mg_virtual" alanına atanmalıdır. "Sihirli Sanal Tablolar" bölümüne bakın.
aşağıdaki bölüm. "Nasıl" argümanı da "mg_type" alanında saklanır. Değeri
içinde bulunan "PERL_MAGIC_foo" makro kümesinden "nasıl" seçilmelidir perl.h. Bunu not et
bu makrolar eklenmeden önce, Perl dahilileri doğrudan karakter değişmezlerini kullanırdı, bu yüzden
yerine 'U' büyüsüne atıfta bulunan eski kod veya belgelerle zaman zaman karşılaşabilirsiniz.
örneğin "PERL_MAGIC_uvar" yerine.
"obj" argümanı "MAGIC" yapısının "mg_obj" alanında saklanır. Ya değilse
"sv" argümanıyla aynı şekilde, "obj" nesnesinin referans sayısı artırılır. Eğer
aynıysa veya "nasıl" argümanı "PERL_MAGIC_arylen" ise veya NULL ise
işaretçi, ardından "obj" yalnızca, referans sayısı artırılmadan saklanır.
Bir SV'ye sihir eklemenin daha esnek bir yolu için perlapi'deki "sv_magicext" bölümüne de bakın.
Bir "HV" ye sihir ekleme işlevi de vardır:
void hv_magic(HV *hv, GV *gv, int nasıl);
Bu basitçe "sv_magic"i çağırır ve "gv" argümanını bir "SV"ye zorlar.
Bir SV'den büyüyü kaldırmak için sv_unmagic işlevini çağırın:
int sv_unmagic(SV *sv, int türü);
"Tür" argümanı, "SV" ilk yapıldığında "nasıl" değerine eşit olmalıdır.
büyülü.
Ancak, "sv_unmagic"in belirli bir "tür"ün tüm büyüsünü "SV"den kaldırdığını unutmayın. Eğer
sihirli sanal tabloya dayalı olarak yalnızca belirli bir "tür" büyüsünü kaldırmak istiyorsanız,
Bunun yerine "sv_unmagicext":
int sv_unmagicext(SV *sv, int türü, MGVTBL *vtbl);
sihirli Sanal tablolar
"MAGIC" yapısındaki "mg_virtual" alanı, bir "MGVTBL" işaretçisidir.
işlev işaretçilerinin yapısı ve çeşitli işlemleri işlemek için "Sihirli Sanal Tablo" anlamına gelir.
bu değişkene uygulanabilecek işlemler.
"MGVTBL", aşağıdaki rutin türlere yönelik beş (veya bazen sekiz) işaretçiye sahiptir:
int (*svt_get)(SV* sv, MAGIC* mg);
int (*svt_set)(SV* sv, MAGIC* mg);
U32 (*svt_len)(SV* sv, MAGIC* mg);
int (*svt_clear)(SV* sv, MAGIC* mg);
int (*svt_free)(SV* sv, MAGIC* mg);
int (*svt_copy)(SV *sv, MAGIC* mg, SV *nsv,
const char *isim, I32 isim);
int (*svt_dup)(MAGIC *mg, CLONE_PARAMS *param);
int (*svt_local)(SV *nsv, MAGIC *mg);
Bu MGVTBL yapısı, derleme zamanında ayarlanır. perl.h ve şu anda 32 çeşit var.
Bu farklı yapılar, ek performans gösteren çeşitli rutinlere yönelik işaretçiler içerir.
hangi işlevin çağrıldığına bağlı olarak eylemler.
İşlev işaretçisi Yapılan işlem
------------------------------------------
svt_get SV'nin değeri belirlenmeden önce bir şeyler yapın
alındı.
svt_set SV'ye bir değer atandıktan sonra bir şeyler yapın.
svt_len SV'nin uzunluğu hakkında rapor verin.
svt_clear SV'nin temsil ettiği bir şeyi temizleyin.
svt_free SV ile ilişkili tüm ekstra depolama alanını boşaltın.
svt_copy bağlı bir öğeye bağlı sihirli değişkeni kopyala
svt_dup, iş parçacığı klonlama sırasında sihirli bir yapıyı çoğaltıyor
svt_local sihri 'yerel' sırasında yerel değere kopyala
Örneğin, "vtbl_sv" olarak adlandırılan MGVTBL yapısı ("mg_type" a karşılık gelir).
"PERL_MAGIC_sv") şunları içerir:
{ magic_get, magic_set, magic_len, 0, 0 }
Bu nedenle, bir SV'nin büyülü ve "PERL_MAGIC_sv" türünde olduğu belirlendiğinde,
işlem gerçekleştirilirken "magic_get" rutini çağrılır. Tüm çeşitli rutinler
çeşitli büyülü türler için "magic_" ile başlar. NOT: sihirli rutinler
Perl API'sinin bir parçası olarak kabul edilir ve Perl kitaplığı tarafından dışa aktarılamaz.
Son üç yuva yeni eklenenlerdir ve kaynak kodu uyumluluğu için
yalnızca MGf_COPY, MGf_DUP veya MGf_LOCAL bayraklarından birinin ayarlanmış olup olmadığı kontrol edilir.
mg_flags. Bu, çoğu kodun bir vtable'ı 5 öğeli bir değer olarak bildirmeye devam edebileceği anlamına gelir.
Bu üçü şu anda yalnızca iş parçacığı kodu tarafından kullanılmaktadır ve son derece tabidir.
değiştirmek için.
Mevcut Sihirli Sanal Tablo türleri şunlardır:
mg_type
(eski tarz karakter ve makro) MGVTBL Büyü türü
-------------------------- --------------------------
\0 PERL_MAGIC_sv vtbl_sv Özel skaler değişken
# PERL_MAGIC_arylen vtbl_arylen Dizi uzunluğu ($#ary)
% PERL_MAGIC_rhash (yok) Kısıtlı için ekstra veri
karmaları
* PERL_MAGIC_debugvar vtbl_debugvar $DB::tek, sinyal, izleme
vars
. PERL_MAGIC_pos vtbl_pos pos() değer
: PERL_MAGIC_symtab (yok) Sembol için ekstra veri
tablolar
< PERL_MAGIC_backref vtbl_backref Zayıf başvuru verileri için
@ PERL_MAGIC_arylen_p (yok) Arileni XPVAV'den çıkarmak için
B PERL_MAGIC_bm vtbl_regexp Boyer-Moore
(hızlı dizi arama)
c PERL_MAGIC_overload_table vtbl_ovrld Aşırı yük tablosunu tutar
(AMT) zulada
D PERL_MAGIC_regdata vtbl_regdata Normal ifade eşleşme konumu verileri
(@+ ve @- değişkenler)
d PERL_MAGIC_regdatum vtbl_regdatum Normal ifade eşleşme konumu verileri
eleman
E PERL_MAGIC_env vtbl_env %ENV karması
e PERL_MAGIC_envelem vtbl_envelem %ENV karma öğesi
f PERL_MAGIC_fm vtbl_regexp Form Hattı
('derlenmiş' biçim)
g PERL_MAGIC_regex_global vtbl_mglob m//g hedefi
H PERL_MAGIC_hints vtbl_hints %^H karma
h PERL_MAGIC_hintselem vtbl_hintselem %^H karma öğesi
I PERL_MAGIC_isa vtbl_isa @ISA dizisi
i PERL_MAGIC_isaelem vtbl_isaelem @ISA dizi öğesi
k PERL_MAGIC_nkeys vtbl_nkeys skaler(keys()) değeri
L PERL_MAGIC_dbfile (yok) Hata Ayıklayıcı %_
l PERL_MAGIC_dbline vtbl_dbline Hata Ayıklayıcı %_
eleman
N PERL_MAGIC_shared (yok) Konular arasında paylaşıldı
n PERL_MAGIC_shared_scalar (yok) Konular arasında paylaşıldı
o PERL_MAGIC_collxfrm vtbl_collxfrm Yerel ayar dönüşümü
P PERL_MAGIC_tied vtbl_pack Bağlı dizi veya karma
p PERL_MAGIC_tiedelem vtbl_packelem Bağlı dizi veya karma öğe
q PERL_MAGIC_tiedscalar vtbl_packelem Bağlı skaler veya tanıtıcı
r PERL_MAGIC_qr vtbl_regexp Önceden derlenmiş qr// normal ifade
S PERL_MAGIC_sig (yok) %SIG karma
s PERL_MAGIC_sigelem vtbl_sigelem %SIG karma öğesi
t PERL_MAGIC_taint vtbl_taint Kusurluluk
U PERL_MAGIC_uvar vtbl_uvar
uzantıları
u PERL_MAGIC_uvar_elem (yok) Tarafından kullanılmak üzere ayrılmıştır
uzantıları
V PERL_MAGIC_vstring (yok) SV, vstring değişmez değeriydi
v PERL_MAGIC_vec vtbl_vec vec() değer
w PERL_MAGIC_utf8 vtbl_utf8 Önbelleğe alınmış UTF-8 bilgileri
x PERL_MAGIC_substr vtbl_substr substr() değer
y PERL_MAGIC_defelem vtbl_defelem Gölge "foreach" yineleyicisi
değişken / akıllı parametre
canlandırma
\ PERL_MAGIC_lvref vtbl_lvref Değer referansı
inşaatçı
] PERL_MAGIC_checkcall vtbl_checkcall Çağrının satır içi/mutasyonu
bu özgeçmişe
~ PERL_MAGIC_ext (yok) Tarafından kullanılabilir
uzantıları
Tabloda hem büyük hem de küçük harf varsa, büyük harf
tipik olarak bir tür bileşik türü (bir liste veya karma) temsil etmek için kullanılır ve
küçük harf, bu bileşik türden bir öğeyi temsil etmek için kullanılır. Bazı dahili
kod bu durum ilişkisini kullanır. Ancak, 'v' ve 'V' (vec ve v-string)
hiçbir şekilde ilgili değil.
"PERL_MAGIC_ext" ve "PERL_MAGIC_uvar" sihirli türleri, özellikle
uzantıları vardır ve Perl tarafından kullanılmayacaktır. Uzantılar "PERL_MAGIC_ext" büyüsünü kullanabilir
özel bilgileri değişkenlere (tipik olarak nesneler) 'eklemek' için. Bu özellikle
kullanışlıdır çünkü normal perl kodunun bu özel bilgiyi bozmasının bir yolu yoktur.
(bir karma nesnenin fazladan öğelerini kullanmanın aksine).
Benzer şekilde, "PERL_MAGIC_uvar" büyüsü şu şekilde kullanılabilir: bağlamak() herhangi bir C işlevini çağırmak için
bir skalerin değerinin kullanıldığı veya değiştirildiği zamandır. "MAGIC"in "mg_ptr" alanı bir
"ufuncs" yapısı:
yapı ufuncs {
I32 (*uf_val)(pTHX_IV, SV*);
I32 (*uf_set)(pTHX_IV, SV*);
IV uf_index;
};
SV okunduğunda veya yazıldığında, "uf_val" veya "uf_set" işlevi çağrılır
ilk argüman olarak "uf_index" ve ikinci olarak SV'ye bir işaretçi ile. Basit bir örnek
"PERL_MAGIC_uvar" büyüsünün nasıl ekleneceği aşağıda gösterilmiştir. Unutulmamalıdır ki ufuncs yapısı
sv_magic tarafından kopyalanır, böylece yığına güvenle tahsis edebilirsiniz.
geçersiz
Umajik(sv)
SV *sv;
ÖNCEKİ:
ufuncs uf yapısı;
KOD:
uf.uf_val = &my_get_fn;
uf.uf_set = &my_set_fn;
uf.uf_index = 0;
sv_magic(sv, 0, PERL_MAGIC_uvar, (char*)&uf, sizeof(uf));
Dizilere "PERL_MAGIC_uvar" eklenmesine izin verilir ancak hiçbir etkisi yoktur.
Karma değerler için, hash anahtarları üzerinde kontrol sağlayan (ama değerler değil) özel bir kanca vardır.
Bu kanca, "ufuncs" içindeki "set" işlevi varsa "PERL_MAGIC_uvar" 'get' sihrini çağırır.
yapı NULL'dur. Kanca, karmaya bir anahtarla erişildiğinde etkinleştirilir
"hv_store_ent", "hv_fetch_ent" işlevleri aracılığıyla bir "SV" olarak belirtilir,
"hv_delete_ent" ve "hv_exists_ent". Anahtara işlevler aracılığıyla bir dize olarak erişme
"..._ent" soneki olmadan kancayı atlar. Hash::Util::FieldHash içinde "GUTS" konusuna bakın
ayrıntılı bir açıklama için.
Birden fazla uzantının "PERL_MAGIC_ext" veya "PERL_MAGIC_uvar" kullanıyor olabileceğini unutmayın.
Magic, uzantıların çakışmayı önlemek için ekstra özen göstermesi önemlidir. Tipik
yalnızca uzantıyla aynı sınıfa kutsanmış nesnelerde sihri kullanmak
yeterli. "PERL_MAGIC_ext" büyüsü için genellikle bir "MGVTBL" tanımlamak iyi bir fikirdir,
tüm alanları 0 olsa bile, bireysel "MAGIC" işaretçileri şu şekilde tanımlanabilir:
sihirli sanal tablolarını kullanarak belirli bir tür sihir. "mg_findex" kolay bir
bunu yapmanın yolu:
STATİK MGVTBL my_vtbl = { 0, 0, 0, 0, 0, 0, 0, 0 };
SİHİRLİ * mg;
if ((mg = mg_findex(sv, PERL_MAGIC_ext, &my_vtbl))) {
/* bu gerçekten bizim, başka bir modülün PERL_MAGIC_ext değil */
my_priv_data_t *priv = (my_priv_data_t *)mg->mg_ptr;
Kendi ID’n ile mağazalarını oluştur
}
Ayrıca, daha önce açıklanan "sv_set*()" ve "sv_cat*()" işlevlerinin değil çağırmak
hedeflerine sihir 'ayarlayın'. Bu, kullanıcı tarafından telefon numarası aranarak yapılmalıdır.
"SvSETMAGIC()" makrosu bu işlevleri çağırdıktan sonra veya "sv_set*_mg()" komutlarından birini kullanarak
veya "sv_cat*_mg()" işlevleri. Benzer şekilde, genel C kodu "SvGETMAGIC()" makrosunu çağırmalıdır.
işlevlerde harici kaynaklardan elde edilen bir SV kullanıyorlarsa, herhangi bir 'get' büyüsünü çağırmak için
bu sihirle uğraşmaz. Bu işlevlerin açıklaması için bkz. Örneğin,
"sv_cat*()" işlevlerine yapılan çağrıların ardından genellikle "SvSETMAGIC()" gelmesi gerekir, ancak
uygulamaları 'get' büyüsünü ele aldığından, önceden bir "SvGETMAGIC()"e ihtiyaçları yoktur.
Bulma sihirli
MAGIC *mg_find(SV *sv, int tipi); /* Bunun sihirli işaretçisini bulur
* tip */
Bu rutin, SV'de depolanan "MAGIC" yapısına bir işaretçi döndürür. SV yaparsa
bu sihirli özelliğe sahip değilse, "NULL" döndürülür. SV'nin birden fazla örneği varsa
o büyülü özellik, ilki iade edilecek. "mg_findex" bulmak için kullanılabilir
Bir SV'nin hem sihirli türüne hem de sihirli sanal tablosuna dayalı "MAGIC" yapısı:
MAGIC *mg_findext(SV *sv, int tipi, MGVTBL *vtbl);
Ayrıca, "mg_find" veya "mg_findex" öğesine geçirilen SV, SVt_PVMG türünde değilse, Perl
dökümü.
int mg_copy(SV* sv, SV* nsv, const char* anahtarı, STRLEN klen);
Bu rutin, "sv"nin ne tür büyülere sahip olduğunu kontrol eder. mg_type alanı bir
büyük harf, ardından mg_obj "nsv"ye kopyalanır, ancak mg_type alanı olarak değiştirilir
küçük harf olsun.
Anlamak the sihirli of bağlı Hash'ler ve Diziler
Bağlı karmalar ve diziler, "PERL_MAGIC_tied" sihirli türünün büyülü canavarlarıdır.
UYARI: 5.004 sürümünden itibaren dizi ve karma erişim işlevlerinin doğru kullanımı
birkaç uyarının anlaşılmasını gerektirir. Bu uyarılardan bazıları aslında hata olarak kabul edilir
API'de, sonraki sürümlerde düzeltilecek ve aşağıda [MAYCHANGE] ile parantez içine alınmıştır. Eğer
Kendinizi bu bölümde bu tür bilgileri uygularken buluyorsanız,
davranış gelecekte, umm, uyarı vermeden değişebilir.
Perl tie işlevi, bir değişkeni çeşitli işlevleri uygulayan bir nesneyle ilişkilendirir.
GET, SET, vb yöntemler. Bir XSUB'dan perl kravat işlevinin eşdeğerini gerçekleştirmek için,
bu davranışı taklit etmelisiniz. Aşağıdaki kod gerekli adımları gerçekleştirir -- ilk olarak
yeni bir karma oluşturur ve ardından sınıfa kutsadığı ikinci bir karma oluşturur
hangi kravat yöntemlerini uygulayacak. Son olarak iki hash'i birbirine bağlar ve geri döner.
yeni bağlı karmaya bir referans. Aşağıdaki kodun TIEHASH'ı ARAMADIĞINI unutmayın.
MyTie sınıfındaki yöntem - ayrıntılar için "Perl Rutinlerini C Programlarından Çağırma" bölümüne bakın
Bunun nasıl yapılacağı hakkında.
SV*
Mytie()
ÖNCEKİ:
HV *karma;
YG * zula;
SV *bağ;
KOD:
karma = yeniHV();
bağ = newRV_noinc((SV*)newHV());
stash = gv_stashpv("Tie'm", GV_ADD);
sv_bless(bağla, sakla);
hv_magic(hash, (GV*)tie, PERL_MAGIC_tied);
RETVAL = newRV_noinc(karma);
ÇIKIŞ:
GERİ DÖN
"av_store" işlevi, bağlı bir dizi argümanı verildiğinde, yalnızca
"mg_copy" kullanarak "depolanacak" değere dizileyin. Ayrıca NULL döndürebilir ve şunu belirtir:
değerin aslında dizide saklanması gerekmediği. [MAYCHANGE] Bir aramadan sonra
bağlı bir dizide "av_store" için, arayan kişinin genellikle "mg_set(val)" öğesini çağırması gerekir.
aslında TIEARRAY nesnesinde perl düzeyi "STORE" yöntemini çağırın. "av_store" yaptıysa
NULL döndürür, bir "SvREFCNT_dec(val)" çağrısı da genellikle bir
bellek sızıntısı. [/DEĞİŞEBİLİR]
Önceki paragraf, "hv_store" kullanılarak bağlı karma erişime kelimesi kelimesine uygulanabilir ve
"hv_store_ent" de çalışır.
"av_fetch" ve ilgili "hv_fetch" ve "hv_fetch_ent" karma işlevleri aslında
büyüsü "mg_copy" kullanılarak başlatılan tanımsız bir ölümlü değeri döndür. Not
bu şekilde döndürülen değerin, zaten ölümlü olduğu için yeniden tahsis edilmesi gerekmez.
[DEĞİŞİKLİK YAPILABİLİR] Ancak, döndürülen değerde "mg_get()" öğesini çağırmanız gerekir.
aslında temeldeki TIE nesnesinde perl düzeyi "FETCH" yöntemini çağırır. Benzer şekilde,
muhtemelen uygun bir değer atadıktan sonra, dönüş değerinde "mg_set()" öğesini de çağırabilirsiniz.
TIE nesnesinde "STORE" yöntemini çağıracak olan "sv_setsv" kullanarak ona.
[/DEĞİŞEBİLİR]
[MAYCHANGE] Başka bir deyişle, dizi veya karma getirme/depolama işlevleri gerçekten getirmez ve
bağlı diziler ve karmalar durumunda gerçek değerleri saklayın. Sadece "mg_copy" olarak adlandırırlar.
"depolanması" veya "getirilmesi" amaçlanan değerlere sihir ekleyin. Daha sonra aramalar
"mg_get" ve "mg_set" aslında temeldeki TIE yöntemlerini çağırma işini yapar.
nesneler. Böylece sihirli mekanizma şu anda dizilere bir tür tembel erişim uygular.
ve karmalar.
Şu anda (Perl 5.004 sürümünden itibaren), karma ve dizi erişim işlevlerinin kullanımı şunları gerektirir:
kullanıcının "normal" karmalar ve diziler üzerinde mi yoksa
onların bağlı varyantları. API, her ikisine de daha şeffaf erişim sağlamak için değiştirilebilir
gelecek sürümlerde bağlı ve normal veri türleri. [/DEĞİŞEBİLİR]
TIEARRAY ve TIEHASH arayüzlerinin sadece şekerden ibaret olduğunu anlasanız iyi edersiniz.
tek tip karma ve dizi sözdizimini kullanırken bazı Perl yöntemi çağrılarını çağırın. Kullanımı
bu şeker bir miktar ek yük getirir (tipik olarak kişi başına yaklaşık iki ila dört ekstra işlem kodu
FETCH/STORE işlemi, gerekli tüm ölümlü değişkenlerin yaratılmasına ek olarak
yöntemleri çağırın). TIE yöntemlerinin kullanılması durumunda, bu ek yük nispeten küçük olacaktır.
Kendileri önemli, ancak yalnızca birkaç ifade uzunluğundaysa, genel gider
önemsiz ol.
yerelleştirme değişiklikler
Perl'in çok kullanışlı bir yapısı var
{
yerel $var = 2;
Kendi ID’n ile mağazalarını oluştur
}
Bu yapı yaklaşık olarak eşdeğerdir
{
benim $eskivarım = $var;
$var = 2;
Kendi ID’n ile mağazalarını oluştur
$var = $eskivar;
}
En büyük fark, ilk yapının başlangıç değerini eski haline getirmesidir.
$var, kontrolün bloktan nasıl çıktığına bakılmaksızın: "goto", "return", "die"/"eval", vb.
Aynı zamanda biraz daha verimlidir.
Perl API aracılığıyla C'den benzer bir görevi gerçekleştirmenin bir yolu vardır: sözde blok, ve
bazı değişikliklerin sonunda otomatik olarak geri alınmasını, açık veya
yerel olmayan bir çıkış yoluyla (üzerinden ) (Kalıp). blok-benzeri yapı bir çift tarafından oluşturulur
"ENTER"/"LEAVE" makroları (perlcall'da "Bir Skaler Döndürme" konusuna bakın). Böyle bir yapı olabilir
bazı önemli yerelleştirilmiş görevler veya mevcut bir görev (sınırlar gibi) için özel olarak oluşturulmuş
Perl alt yordamını/blokunu veya TMP'leri serbest bırakmak için mevcut bir çifti) kullanılabilir.
(İkinci durumda, ek yerelleştirmenin ek yükü neredeyse ihmal edilebilir olmalıdır.)
Herhangi bir XSUB'un otomatik olarak bir "GİRİŞ"/"ÇIKIŞ" çiftine dahil edildiğini unutmayın.
İçinde böyle bir sözde blok aşağıdaki hizmet mevcuttur:
"KAYDET (int i)"
"KAYDETIV(IV i)"
"SAVEI32(I32 i)"
"TASARRUF (uzun i)"
Bu makrolar, sonunda "i" tamsayı değişkeninin değerini geri yüklemek için şeyler düzenler.
parça sözde blok.
SAVESPTR(ler)
KAYDETPPTR(p)
Bu makrolar, "s" ve "p" işaretçilerinin değerini geri yüklemek için bir şeyler düzenler. "s" olmalı
"SV*" ve geri dönüşümden kurtulan türden bir işaretçi, "p" yapabilmelidir
"char *" ve geri dönüşümden kurtulun.
"SAVEFREESV(SV *sv)"
"sv" refcount'unun sonunda azaltılacaktır. sözde blok. Bu benzer
"sv_2mortal" için, aynı zamanda gecikmeli bir "SvREFCNT_dec" yapmak için bir mekanizmadır.
Bununla birlikte, "sv_2mortal", "sv" öğesinin ömrünü sv'nin başlangıcına kadar uzatırken,
sonraki ifade, "SAVEFREESV", onu çevreleyen kapsamın sonuna kadar genişletir. Bunlar
yaşamları çılgınca farklı olabilir.
Ayrıca "SAVEMORTALIZV" ile karşılaştırın.
"SAVEMORTALİZE ET (SV *sv)"
Tıpkı "SAVEFREESV" gibi, ancak geçerli kapsamın sonunda "sv" yerine
referans sayısını azaltıyor. Bu genellikle "sv" yi canlı tutma etkisine sahiptir.
Şu anda canlı kapsamı çağıran ifadenin yürütülmesi bitene kadar.
"KAYDEDİLMEZOP(OP *op)"
"OP *" işlem_ücretsiz()sonunda ed sözde blok.
TASARRUFSIZPV(p)
"p" ile gösterilen bellek parçası güvenli ücretsiz()sonunda ed yalancı
blok.
"SAVECLEARSV(SV *sv)"
Geçerli not defterinde, sonunda "sv"ye karşılık gelen bir yuvayı temizler.
sözde blok.
"SAVEDELETE(HV *hv, karakter *anahtar, I32 uzunluk)"
"hv"nin "anahtar" anahtarı, sonunda silinir. sözde blok. tarafından işaret edilen dize
"anahtar" güvenli ücretsiz()ed. eğer biri varsa anahtar kısa ömürlü depolamada, karşılık gelen
string şu şekilde yeniden tahsis edilebilir:
SAVEDELETE(PL_defstash, savepv(tmpbuf), strlen(tmpbuf));
"SAVEDESTRUCTOR(DESTRUCTORFUNC_NOCONTEXT_t f, geçersiz *p)"
Sonunda sözde blok "f" işlevi, yalnızca "p" bağımsız değişkeni ile çağrılır.
"SAVEDESTRUCTOR_X(DESTRUCTORFUNC_t f, geçersiz *p)"
Sonunda sözde blok "f" işlevi örtük bağlamla çağrılır
argüman (varsa) ve "p".
"SAVESTACK_POS()"
Perl dahili yığınındaki geçerli ofset (cf. "SP"), sonunda geri yüklenir.
sözde blok.
Aşağıdaki API listesi işlevleri içerir, bu nedenle
açıkça değiştirilebilir veriler (C işaretçileri veya Perlish "GV *"ler). Yukarıdakiler nerede
makrolar "int" alır, benzer bir işlev "int *" alır.
"SV* save_scalar(GV *gv)"
Perl kodu "yerel $gv" ile eşdeğerdir.
"AV* save_ary(GV *gv)"
"HV* save_hash(GV *gv)"
"save_scalar"a benzer, ancak @gv ve %gv'yi yerelleştirin.
"void save_item(SV *item)"
Geçerli "ENTER"/"LEAVE" çıkışında "SV"nin geçerli değerini çoğaltır
sözde blok saklanan değeri kullanarak "SV" değerini geri yükleyecektir. idare etmez
büyü. Büyü etkileniyorsa "save_scalar" kullanın.
"void save_list(SV **sarg, I32 maxsarg)"
"SV*" dizisinin "sarg" dizisi aracılığıyla birden çok argüman alan bir "save_item" çeşidi
"maxsarg" uzunluğundadır.
"SV* save_svref(SV **sptr)"
"save_scalar"a benzer, ancak bir "SV *" öğesini eski durumuna getirir.
"void save_aptr(AV **aptr)"
"void save_hptr(HV **hptr)"
"save_svref"e benzer, ancak "AV *" ve "HV *" öğelerini yerelleştirin.
"Alias" modülü, içindeki temel türlerin yerelleştirilmesini uygular. arayanın kapsam.
Kapsayıcı kapsamdaki şeyleri nasıl yerelleştirecekleriyle ilgilenen kişiler,
oraya da bak.
Altyordamlar
XSUB'lar ve the Tartışma Yığın
XSUB mekanizması, Perl programlarının C alt rutinlerine erişmesinin basit bir yoludur. bir XSUB
rutin, Perl programından gelen argümanları içeren bir yığına ve bunu yapmanın bir yoluna sahip olacaktır.
Perl veri yapılarından bir C eşdeğerine eşleyin.
Yığın argümanlarına, "n"'inci yığını döndüren ST(n) makrosu aracılığıyla erişilebilir.
argüman. Argüman 0, Perl altyordam çağrısında iletilen ilk argümandır. Bunlar
bağımsız değişkenler "SV*"dir ve "SV*" ifadesinin kullanıldığı her yerde kullanılabilir.
Çoğu zaman, C rutininin çıktısı RETVAL kullanılarak işlenebilir ve
OUTPUT yönergeleri. Ancak, argüman yığınının henüz olmadığı bazı durumlar vardır.
tüm dönüş değerlerini işlemek için yeterince uzun. Bir örnek, POSIX'tir. tzname() hangisini ara
hiçbir argüman almaz, ancak yerel saat diliminin standart ve yaz saati olmak üzere iki tane döndürür
kısaltmalar.
Bu durumu ele almak için, PPCODE yönergesi kullanılır ve yığın, aşağıdakiler kullanılarak genişletilir:
makro:
GENİŞLET(SP, sayı);
burada "SP", yığın işaretçisinin yerel kopyasını temsil eden makrodur ve "num",
yığının genişletilmesi gereken öğelerin sayısı.
Artık yığında yer olduğuna göre, "PUSHs" makrosu kullanılarak değerler üzerine itilebilir. bu
itilen değerlerin genellikle "ölümcül" olması gerekir (Bkz. "Referans Sayıları ve Ölüm Oranı"):
PUSH'ler(sv_2mortal(newSViv(an_integer)))
PUSH'ler(sv_2mortal(newSVuv(an_unsigned_integer)))
PUSH'ler(sv_2mortal(newSVnv(a_double)))
PUSH'ler(sv_2mortal(newSVpv("Bazı Dize",0)))
/* Son örnek daha iyi yazılmış olsa da
* verimli: */
PUSH'ler(newSVpvs_flags("Bazı Diziler", SVs_TEMP))
Ve şimdi Perl programı "tzname" çağırıyor, iki değer aşağıdaki gibi atanacak:
($standart_kısaltma, $yaz_kısaltma) = POSIX::tzname;
Değerleri yığına aktarmanın alternatif (ve muhtemelen daha basit) bir yöntemi,
makro:
XPUSH'ler(SV*)
Bu makro, gerekirse yığını sizin için otomatik olarak ayarlar. Böylece, gerek yok
yığını genişletmek için "EXTEND" arayın.
Bu belgenin önceki sürümlerindeki önerilerine rağmen, "(X)PUSH[iunp]" makroları
vardır değil birden çok sonuç döndüren XSUB'lara uygundur. Bunun için, ya
Yukarıda gösterilen "(X)PUSHs" makroları veya bunun yerine yeni "m(X)PUSH[iunp]" makrolarını kullanın; görmek
"Perl yığınına bir C değeri koymak".
Daha fazla bilgi için perlxs ve perlxstut'a danışın.
Otomatik yükleme ile XSUB'lar
AUTOLOAD rutini, Perl alt rutinlerinde olduğu gibi bir XSUB ise, Perl tam nitelikli
XSUB paketinin $AUTOLOAD değişkenindeki otomatik yüklenen alt yordamın adı.
Ancak aynı bilgiyi XSUB'un belirli alanlarına da koyar:
HV *zula = CvSTASH(cv);
const char *alt ad = SvPVX(cv);
STRLEN isim_uzunluğu = SvCUR(cv); /* bayt olarak */
U32 is_utf8 = SvUTF8(cv);
"SvPVX(cv)", paket dahil değil, yalnızca alt adı içerir. OTOMATİK YÜKLEME için
UNIVERSAL veya onun üst sınıflarından birindeki rutin, "CvSTASH(cv)", bir işlem sırasında NULL döndürür.
var olmayan bir pakette yöntem çağrısı.
not: $AUTOLOAD ayarı, XS AUTOLOAD alt öğelerini desteklemeyen 5.6.1'de çalışmayı durdurdu
hiç. Perl 5.8.0, XSUB'un kendisinde alanların kullanımını tanıttı. Perl 5.16.0 geri yüklendi
$AUTOLOAD ayarı. 5.8-5.14'ü desteklemeniz gerekiyorsa, XSUB'un alanlarını kullanın.
çağrı Perl Rutinler itibaren içinde C Programlar
Bir C içinden Perl altyordamını çağırmak için kullanılabilecek dört rutin vardır.
programı. Bu dördü:
I32 call_sv(SV*, I32);
I32 call_pv(const karakter*, I32);
I32 call_method(const karakter*, I32);
I32 call_argv(const karakter*, I32, karakter**);
En sık kullanılan rutin "call_sv"dir. "SV*" bağımsız değişkeni,
çağrılacak Perl alt yordamı veya alt yordama bir başvuru. ikinci argüman
altyordamın çağrıldığı bağlamı kontrol eden bayraklardan oluşur.
altyordam argümanları iletilmiyor, hataların nasıl yakalanması gerektiği ve nasıl
dönüş değerlerini tedavi edin.
Dört yordamın tümü, alt yordamın Perl'de döndürdüğü argüman sayısını döndürür.
yığını.
Bu rutinler Perl v5.6.0'dan önce "perl_call_sv" vb. olarak adlandırılıyordu, ancak bu isimler
artık kullanımdan kaldırıldı; aynı ada sahip makrolar uyumluluk için sağlanmıştır.
Bu rutinlerden herhangi birini ("call_argv" hariç) kullanırken, programcı
Perl yığını. Bunlar, aşağıdaki makroları ve işlevleri içerir:
dSP
SP
PUSHMARK()
GERİ KOY
İSPANYA
ENTER
KAYDETTMPS
ÜCRETSİZ
TERK
XPUS*()
POP*()
C'den Perl'e çağrı kurallarının ayrıntılı bir açıklaması için, perlcall'a danışın.
koymak a C değer on Perl yığın
Bir çok işlem kodu (bu, dahili Perl yığın makinesinde temel bir işlemdir)
yığında bir SV*. Ancak, bir optimizasyon olarak karşılık gelen SV (genellikle)
her seferinde yeniden yaratılır. İşlem kodları, özel olarak atanmış SV'leri yeniden kullanır (hedefs) olan (bir
sonucu) sürekli olarak serbest bırakılmaz/yaratılmaz.
Hedeflerin her biri yalnızca bir kez oluşturulur (ancak aşağıdaki "Scratchpad'ler ve özyineleme" konusuna bakın) ve
Bir işlem kodunun yığına bir tamsayı, bir çift veya bir dize koyması gerektiğinde, yalnızca
karşılık gelen parçaları hedef ve koyar hedef yığın üzerinde.
Bu hedefi yığına koyacak makro "PUSHTARG" dır ve bazılarında doğrudan kullanılır.
opcode'lar ve dolaylı olarak "(X)PUSH[iunp]" aracılığıyla kullanan zilyonlarca diğerinde dolaylı olarak.
Hedef yeniden kullanıldığından, birden fazla değeri ekrana basarken dikkatli olmalısınız.
yığın. Aşağıdaki kod düşündüğünüzü yapmayacaktır:
XPUSMerhaba(10);
XPUSMerhaba(20);
Bu, "TARG"ı 10'a ayarlayın, bir işaretçiyi yığının üzerine "TARG" olarak itin; "TARG" olarak ayarlayın
20'ye kadar, yığının üzerine "TARG" işaretçisini itin. İşlemin sonunda yığın
10 ve 20 değerlerini içermez, ancak aslında "TARG" için iki işaretçi içerir;
20'ye ayarladık.
Birden fazla farklı değer itmeniz gerekiyorsa, o zaman "(X)PUSH'ları" kullanmalısınız.
veya hiçbiri "TARG" kullanmayan yeni "m(X)PUSH[iunp]" makrolarını kullanın.
"(X)PUSH'lar" makroları, "XSUB'lar ve
Argüman Yığını", genellikle "ölümcül" olması gerekir. Yeni "m(X)PUSH[iunp]" makroları
sizin için yeni bir ölümlü yaratarak bunu başarmak biraz daha kolay ("(X)PUSHmortal" aracılığıyla),
bunu yığının üzerine itin ("mXPUSH[iunp]" durumunda gerekirse genişletin)
makrolar) ve ardından değerini ayarlayın. Bu nedenle, örneği "düzeltmek" için bunu yazmak yerine
yukarıda:
XPUSH'ler(sv_2mortal(yeniSViv(10)))
XPUSH'ler(sv_2mortal(yeniSViv(20)))
basitçe yazabilirsiniz:
mXPUSHI(10)
mXPUSHI(20)
İlgili bir notta, "(X)PUSH[iunp]" kullanırsanız, o zaman bir "dTARG" a ihtiyacınız olacak.
"*PUSH*" makrolarının yerel değişkeni kullanabilmesi için değişken bildirimleriniz
"TARG". Ayrıca bkz. "dTARGET" ve "dXSTARG".
not defterleri
SV'lerin ne zaman olduğu sorusu devam ediyor. hedefişlem kodları için s oluşturulur. bu
cevap, geçerli birim - bir alt program veya bir dosya (işlem kodları için) olduğunda yaratıldıklarıdır.
alt programların dışındaki ifadeler için)-- derlenir. Bu süre zarfında özel bir anonim
Geçerli birim için karalama defteri adı verilen Perl dizisi oluşturulur.
Bir karalama defteri, geçerli birim için sözcüksel olan ve hedef olan SV'leri tutar.
işlem kodları. Bu belgenin önceki bir sürümü, bir SV'nin yaşadığı sonucuna varılabileceğini belirtti.
bayraklarına bakarak bir karalama defterinde: sözlüklerin "SVs_PADMY" seti vardır ve hedefvar
"SVs_PADTMP" seti. Ama bu hiçbir zaman tam olarak doğru olmadı. "SVs_PADMY" bir
artık herhangi bir pedde bulunmayan değişken. Sırasında hedef"SVs_PADTMP" setine sahipler,
ayrıca bir pad'de hiç bulunmamış değişkenler üzerinde de ayarlanabilir, ancak yine de
hedefs. Perl 5.21.5'ten itibaren "SVs_PADMY" bayrağı artık kullanılmamaktadır ve 0 olarak tanımlanmıştır.
"SvPADMY()" artık "SVs_PADTMP" içermeyen her şey için true değerini döndürür.
OP'ler arasındaki yazışmalar ve hedefs 1'e 1 değil. Derlemedeki farklı OP'ler
Ünitenin ağacı, beklenen hedefle çelişmeyecekse aynı hedefi kullanabilir.
geçici hayat.
not defterleri ve yineleme
Aslında derlenmiş bir birimin karalama defteri AV'ye bir işaretçi içerdiği %100 doğru değildir.
Aslında (başlangıçta) bir öğenin AV'sine bir işaretçi içerir ve bu öğe
karalama defteri AV. Neden ekstra bir dolaylı seviyeye ihtiyacımız var?
Cevap yineleme, ve belki Konuları. Her ikisi de birkaç yürütme oluşturabilir
işaretçiler aynı alt programa girer. Altyordam-çocuk için üzerine yazmayın
alt rutin-ebeveyn için geçiciler (ömrü çocuğa yapılan çağrıyı kapsar),
ebeveyn ve çocuğun farklı not defterleri olmalıdır. (Ve sözlükler şöyle olmalı
neyse ayrı!)
Böylece her bir alt program bir dizi karalama defteri (1 uzunluğunda) ile doğar. Her girişte
alt programda, özyinelemenin mevcut derinliğinin
bu dizinin uzunluğu ve varsa, yeni karalama defteri oluşturulur ve diziye itilir.
The hedefBu karalama defterindeki 'ler "undef" lerdir, ancak zaten doğru ile işaretlenmiştir
bayraklar.
Bellek Tahsis
Tahsis
Perl API işlevleriyle kullanılması amaçlanan tüm bellek, aşağıdakiler kullanılarak manipüle edilmelidir.
Bu bölümde açıklanan makrolar. Makrolar, aralarında gerekli şeffaflığı sağlar.
perl içinde kullanılan gerçek malloc uygulamasındaki farklılıklar.
Perl ile dağıtılan malloc sürümünü etkinleştirmeniz önerilir. o
ayırma isteklerini karşılamak için çeşitli boyutlarda ayrılmamış bellek havuzları tutar
daha hızlı bir şekilde. Ancak bazı platformlarda sahte malloc veya ücretsiz hatalara neden olabilir.
Aşağıdaki üç makro, başlangıçta bellek ayırmak için kullanılır:
Newx(işaretçi, sayı, tür);
Newxc(işaretçi, sayı, tür, yayın);
Newxz(işaretçi, sayı, tür);
İlk argüman "işaretçi", yeni değişkene işaret edecek bir değişkenin adı olmalıdır.
Tahsis edilen bellek.
İkinci ve üçüncü argümanlar "sayı" ve "tür", belirtilen türden kaç tane olduğunu belirtir.
veri yapısı tahsis edilmelidir. "type" bağımsız değişkeni "sizeof" öğesine iletilir. bu
"Newxc" için son argüman, "cast", "işaretçi" argümanı farklıysa kullanılmalıdır
"tür" argümanından.
"Newx" ve "Newxc" makrolarından farklı olarak, "Newxz" makrosu tüm öğeleri sıfırlamak için "memzero"yu çağırır.
yeni ayrılan bellek.
Yeniden tahsis
Yenile(işaretçi, sayı, tür);
Renewc(işaretçi, sayı, tür, yayın);
Güvenli ücretsiz(işaretçi)
Bu üç makro, bir bellek arabellek boyutunu değiştirmek veya bir bellek parçasını boşaltmak için kullanılır.
daha uzun süre gerekli. "Yenileme" ve "Yenileme" argümanları "Yeni" ve "Yeni" argümanları ile eşleşir.
"sihirli çerez" argümanına ihtiyaç duymamanın istisnası.
Hareketli
Taşı(kaynak, hedef, sayı, tür);
Kopya(kaynak, hedef, sayı, tür);
Sıfır(hedef, sayı, tür);
Bu üç makro, önceden ayrılmış belleği taşımak, kopyalamak veya sıfırlamak için kullanılır. bu
"source" ve "hedef" argümanları, kaynak ve hedef başlangıç noktalarına işaret eder. Perl
"tür" veri yapısının boyutunun "sayı" örneklerini taşır, kopyalar veya sıfırlar
("sizeof" işlevini kullanarak).
PerliO
Perl'in en son geliştirme sürümleri, Perl's'i kaldırmayı deniyor.
"normal" standart G/Ç paketine bağımlılık ve diğer stdio uygulamalarının
kullanılacak. Bu, daha sonra hangisini çağırıyorsa onu çağıran yeni bir soyutlama katmanı oluşturmayı içerir.
stdio Perl uygulaması ile derlendi. Tüm XSUB'lar artık şuradaki işlevleri kullanmalıdır:
PerliIO soyutlama katmanı ve ne tür bir stdio olduğu hakkında herhangi bir varsayımda bulunmamak
Kullanılan.
PerlIO soyutlamasının tam açıklaması için perlapio'ya danışın.
Derleyen kod
Kod ağaç
Burada, kodunuzun Perl tarafından dönüştürüldüğü dahili formu açıklıyoruz. Basit bir şekilde başlayın
örnek:
$a = $b + $c;
Bu, şuna benzer bir ağaca dönüştürülür:
atamak
/\
+ $bir
/\
$b $c
(ama biraz daha karmaşık). Bu ağaç, Perl'in kodunuzu ayrıştırma şeklini yansıtır, ancak
infaz emri ile ilgisi yoktur. Geçmekte olan ek bir "iş parçacığı" var
düğümlerin yürütme sırasını gösteren ağacın düğümleri. bizim basitleştirilmiş
yukarıdaki örnek şuna benziyor:
$b ---> $c ---> + ---> $a ---> atama
Ancak "$a = $b + $c" için gerçek derleme ağacı ile durum farklıdır: bazı düğümler optimize
uzakta. Sonuç olarak, gerçek ağaç basitleştirilmiş halimizden daha fazla düğüm içeriyor olsa da
örneğin, yürütme sırası örneğimizdeki ile aynıdır.
incelenmesi the ağaç
Perl'inizi hata ayıklama için derlediyseniz (genellikle "-DEBUGGING" ile yapılır).
"Configure" komut satırı), üzerinde "-Dx" belirterek derlenmiş ağacı inceleyebilirsiniz.
Perl komut satırı. Çıktı, düğüm başına birkaç satır alır ve "$b+$c" için şuna benzer:
bu:
5 TİP = ekle ===> 6
HEDEF = 1
BAYRAKLAR = (SCALAR,ÇOCUKLAR)
{
TÜR = boş ===> (4)
(rv2sv idi)
BAYRAKLAR = (SCALAR,ÇOCUKLAR)
{
3 TİP = gvsv ===> 4
BAYRAKLAR = (SKALER)
GV = ana::b
}
}
{
TÜR = boş ===> (5)
(rv2sv idi)
BAYRAKLAR = (SCALAR,ÇOCUKLAR)
{
4 TİP = gvsv ===> 5
BAYRAKLAR = (SKALER)
GV = ana::c
}
}
Bu ağaçta 5 düğüm var ("TYPE" belirteci başına bir tane), bunlardan yalnızca 3 tanesi optimize edilmedi
(sol sütundaki sayı başına bir tane). Verilen düğümün yakın çocukları karşılık gelir
aynı girinti düzeyinde "{}" çiftleri, dolayısıyla bu liste ağaca karşılık gelir:
eklemek
/\
sıfır sıfır
| |
gvsv gvsv
Yürütme sırası "===>" işaretleriyle belirtilir, dolayısıyla "3 4 5 6"dır (düğüm 6
yukarıdaki listeye dahil edilmiştir), yani "gvsv gvsv ne olursa olsun ekleyin".
Bu düğümlerin her biri bir operasyonu, Perl çekirdeği içindeki temel bir işlemi temsil eder. bu
Her işlemi uygulayan kod, s.*.c Dosyalar; hangi işlev
"gvsv" türü "pp_gvsv" olan op'u uygular, vb. Yukarıdaki ağacın gösterdiği gibi,
farklı operasyonların farklı sayıda çocuğu vardır: "add", birinin yapacağı gibi ikili bir operatördür
bekler ve iki çocuğu vardır. Çeşitli farklı sayıları karşılamak için
Çocuklar, çeşitli op veri yapısı türleri vardır ve bunlar birbirine bağlanır.
Farklı yollar.
En basit op yapısı türü "OP" dir: bunun çocuğu yoktur. tekli operatörler,
"UNOP"ların bir çocuğu var ve bu "op_first" alanıyla gösteriliyor. ikili operatörler
("BINOP"lar) yalnızca bir "op_first" alanına değil, aynı zamanda bir "op_last" alanına da sahiptir. en
karmaşık operasyon türü, herhangi bir sayıda çocuğu olan bir "LISTOP"tur. Bu durumda,
ilk çocuk "op_first" ve son çocuk "op_last" ile gösterilir. çocuklar
Arası, ilk çocuktan gelen "OpSIBLING" işaretçisini yinelemeli olarak izleyerek bulunabilir.
sonuna kadar (ancak aşağıya bakın).
Ayrıca başka işlem türleri de vardır: "PMOP", düzenli bir ifade içerir ve hiçbir
çocuklar ve bir "DÖNGÜ"nün çocukları olabilir veya olmayabilir. "op_children" alanı olmayan ise
sıfır, bir "LISTOP" gibi davranır. Bir "UNOP" aslında bir "boş" ise, meseleleri karmaşıklaştırmak için
Optimizasyondan sonra op (bkz. "Derleme geçişi 2: bağlam yayılımı") yine de
eski tipine göre çocuklar.
Son olarak, bir "LOGOP" veya mantıksal işlem vardır. Bir "LISTOP" gibi, bunun bir veya daha fazla çocuğu var,
ancak bir "op_last" alanı yoktur: bu nedenle "op_first" ve ardından
"OpSIBLING", son çocuğu bulmak için kendisini zincirler. Bunun yerine bir "op_other" alanına sahiptir.
aşağıda açıklanan "op_next" alanıyla karşılaştırılabilir ve bir alternatifi temsil eder
yürütme yolu. "ve", "veya" ve "?" gibi operatörler "LOGOP"lardır. Genel olarak unutmayın,
"op_other", "LOGOP"un doğrudan alt öğelerinden herhangi birine işaret edemez.
5.21.2 sürümünden başlayarak, deneysel tanımlama "-DPERL_OP_PARENT" ile oluşturulan perls
her işlem için "op_moresib" için fazladan bir boole bayrağı ekleyin. Ayarlanmadığında, bu şunu gösterir:
bu, bir "OpSIBLING" zincirindeki son operasyondur. Bu, "op_sibling" alanını serbest bırakır.
ebeveyn operasyonuna geri dönmek için son kardeş. Bu yapı altında, o alan da yeniden adlandırıldı
"op_sibparent" ortak rolünü yansıtacak şekilde. OpSIBLING(o) makrosu bu özel
davranış ve her zaman son kardeşte NULL döndürür. Bu derleme ile op_parent(o)
işlevi, herhangi bir işlemin ebeveynini bulmak için kullanılabilir. Böylece ileriye dönük uyumluluk için
doğrudan "op_sibling"e erişmek yerine her zaman OpSIBLING(o) makrosunu kullanmalıdır.
Ağacı incelemenin başka bir yolu da B::Concise gibi bir derleyici arka uç modülü kullanmaktır.
Derlemek geçmek 1: Kontrol rutinleri
Ağaç, derleyici tarafından oluşturulurken yacc kod onu yapıları besler
tanır. Dan beri yacc aşağıdan yukarıya çalışır, perl derlemesinin ilk geçişi de öyle.
Bu geçişi Perl geliştiricileri için ilginç kılan şey, bazı optimizasyonların
bu geçişte gerçekleştirilir. Bu, "kontrol rutinleri" olarak adlandırılan optimizasyondur. bu
düğüm adları ve karşılık gelen kontrol rutinleri arasındaki yazışmalar,
opcode.pl (bu dosyayı değiştirirseniz "make regen_headers" komutunu çalıştırmayı unutmayın).
Yürütme dışında düğüm tamamen oluşturulduğunda bir kontrol rutini çağrılır.
sipariş iş parçacığı. Şu anda şu anda inşa edilmiş olanlara geri bağlantı olmadığından
düğümü serbest bırakmak ve/veya
üstünde/altında yeni düğümler oluşturma.
Kontrol rutini, ağaca eklenmesi gereken düğümü döndürür (eğer üst
seviye düğümü değiştirilmedi, kontrol rutini argümanını döndürür).
Kural olarak, kontrol rutinlerinin adları "ck_*" olur. Genellikle "yeni * OP" den çağrılırlar.
altyordamlar (veya "dönüştürme") (sırasıyla perly.y).
Derlemek geçmek 1a: sabit katlanır kapılar
Kontrol rutini çağrıldıktan hemen sonra, döndürülen düğüm olup olmadığı kontrol edilir.
derleme zamanı yürütülebilir. Eğer öyleyse (değerin sabit olduğuna karar verilir) hemen
yürütüldü ve bir sabit karşılık gelen alt ağacın "dönüş değeri" olan düğüm
yerine ikame edildi. Alt ağaç silinir.
Sabit katlama gerçekleştirilmediyse, yürütme sırası iş parçacığı oluşturulur.
Derlemek geçmek 2: bağlam yayılma
Derleme ağacının bir parçası için bir bağlam bilindiğinde, bu,
ağaç. Şu anda bağlam 5 değere sahip olabilir (çalışma zamanı bağlamı için 2 yerine):
void, boolean, skaler, liste ve değer. Geçiş 1'in aksine bu geçiş
yukarıdan aşağıya işlenir: Bir düğümün bağlamı, onun çocukları için bağlamı belirler.
Şu anda içeriğe bağlı ek iyileştirmeler gerçekleştirilir. Bundan beri
derleme ağacının geri referanslar içerdiği an ("iş parçacığı" işaretçileri aracılığıyla), düğümler olamaz
Bedava()şimdi. Bu aşamada optimize edilmiş düğümlere izin vermek için, bu tür düğümler boş()birleşik
yerine Bedava()(yani türleri OP_NULL olarak değiştirilir).
Derlemek geçmek 3: gözetleme deliği optimizasyon
Bir alt yordam (veya bir "değerlendirme" veya bir dosya için) için derleme ağacı oluşturulduktan sonra, bir
kod üzerinden ek geçiş gerçekleştirilir. Bu geçiş ne yukarıdan aşağıya ne de aşağıdan yukarıya,
ancak yürütme sırasında (koşullar için ek komplikasyonlarla birlikte).
Bu aşamada gerçekleştirilen optimizasyonlar, geçişte olduğu gibi aynı kısıtlamalara tabidir.
2.
Gözetleme deliği optimizasyonları, global değişken tarafından işaret edilen işlev çağrılarak yapılır.
"PL_peepp". Varsayılan olarak, "PL_peepp" yalnızca global tarafından işaret edilen işlevi çağırır.
"PL_rpeepp" değişkeni. Varsayılan olarak, bu, bazı temel işlem düzeltmelerini ve optimizasyonlarını gerçekleştirir
yürütme sırası op zinciri boyunca ve her bir yan zincir için yinelemeli olarak "PL_rpeepp" öğesini çağırır
ops (koşullardan kaynaklanan). Uzantılar ek optimizasyonlar sağlayabilir veya
düzeltmeler, alt program başına veya özyinelemeli aşamaya aşağıdaki gibi bağlanır:
statik peep_t prev_peepp;
statik void my_peep(pTHX_ OP *o)
{
/* alt program başına özel optimizasyon buraya gelir */
önceki_peepp(aTHX_ o);
/* alt program başına özel optimizasyon da buraya gidebilir */
}
BOT:
önceki_peepp = PL_peepp;
PL_peepp = benim_peep;
statik peep_t prev_rpeepp;
statik void my_rpeep(pTHX_ OP *o)
{
OP *orig_o = o;
for(; o; o = o->op_next) {
/* işlem başına özel optimizasyon buraya gelir */
}
önceki_rpeepp(aTHX_ orig_o);
}
BOT:
önceki_rpeepp = PL_rpeepp;
PL_rpeep = my_rpeep;
Geçmeli koşular
Derleme ağacı, bir runops işlevinde yürütülür. İki runops işlevi vardır,
çalıştır.c ve çöplük.c. "Perl_runops_debug", DEBUGGING ile birlikte kullanılır ve
Aksi takdirde "Perl_runops_standard" kullanılır. yürütülmesi üzerinde hassas kontrol için
derleme ağacı, kendi runops işlevinizi sağlamak mümkündür.
Mevcut runops işlevlerinden birini kopyalamak ve onu kendi zevkinize uyacak şekilde değiştirmek muhtemelen en iyisidir.
ihtiyaçlar. Ardından, XS dosyanızın BOOT bölümüne şu satırı ekleyin:
PL_runops = benim_runoplarım;
Bu işlev, programlarınızın olabildiğince hızlı çalışmasını sağlamak için mümkün olduğunca verimli olmalıdır.
mümkün.
Derleme zamanı kapsam kancalar
Perl 5.14'ten itibaren, kullanarak derleme zamanı sözcüksel kapsam mekanizmasına bağlanmak mümkündür.
"Perl_blockhook_register". Bu şu şekilde kullanılır:
STATİK geçersiz my_start_hook(pTHX_ int dolu);
STATİK BHK my_hooks;
BOT:
BhkENTRY_set(&my_hooks, bhk_start, my_start_hook);
Perl_blockhook_register(aTHX_ &my_hooks);
Bu, her sözcük grubunu derlemenin başlangıcında "my_start_hook" un çağrılmasını ayarlayacaktır.
dürbün. Mevcut kancalar şunlardır:
"void bhk_start(pTHX_ int dolu)"
Bu, yeni bir sözcüksel kapsam başladıktan hemen sonra çağrılır. Perl kodunun aşağıdaki gibi olduğunu unutmayın.
eğer ($x) { ... }
iki kapsam oluşturur: ilki "(" ile başlar ve "dolu == 1" değerine sahiptir, ikincisi başlar
"{" konumunda ve "dolu == 0" değerine sahip. Her ikisi de "}" ile biter, bu nedenle "start" çağrıları ve
"pre/post_end" eşleşecek. Bu kanca tarafından kaydetme yığınına itilen herhangi bir şey
kapsam sona ermeden hemen önce atıldı ("pre_" ve "post_end" kancaları arasında aslında).
"void bhk_pre_end(pTHX_ OP **o)"
Bu, yığının çözülmesinden hemen önce sözcüksel bir kapsamın sonunda çağrılır. o is
kapsamı temsil eden opttree'nin kökü; bu bir çift işaretçidir, böylece yapabilirsiniz
gerekirse OP'yi değiştirin.
"void bhk_post_end(pTHX_ OP **o)"
Bu, yığının çözülmesinden hemen sonra sözcüksel bir kapsamın sonunda çağrılır. o gibidir
üstünde. Varsa, "pre_" ve "post_end" çağrılarının yuvalanmasının mümkün olduğunu unutmayın.
kaydetme yığınında dize değerlendirmeyi çağıran bir şeydir.
"void bhk_eval(pTHX_ OP *const o)"
Bu, bir "eval STRING", "do FILE", "require" derlemeye başlamadan hemen önce çağrılır.
veya "kullanım", değerlendirme ayarlandıktan sonra. o değerlendirmeyi talep eden OP'dir ve
normalde bir "OP_ENTEREVAL", "OP_DOFILE" veya "OP_REQUIRE" olacaktır.
Kanca işlevlerine sahip olduktan sonra, onları yerleştirmek için bir "BHK" yapısına ihtiyacın var. En iyisi bu
statik olarak tahsis etmek için, çünkü kaydettikten sonra serbest bırakmanın bir yolu yoktur. bu
işlev işaretçileri "BhkENTRY_set" makrosu kullanılarak bu yapıya eklenmelidir,
hangi girişlerin geçerli olduğunu gösteren bayrakları da ayarlayacaktır. ayırmanız gerekiyorsa
"BHK" nizi dinamik olarak bir nedenden dolayı, başlamadan önce sıfırladığınızdan emin olun.
Kaydedildikten sonra, bu kancaları kapatacak bir mekanizma yoktur, bu nedenle gerekirse
bunu kendin yapman gerekecek. "%^H" içine bir giriş yapmak muhtemelen en iyi yoldur, bu yüzden
etki sözcüksel olarak kapsamlıdır; ancak "BhkDISABLE" kullanmak da mümkündür ve
Girişleri geçici olarak açıp kapatmak için "BhkENABLE" makroları. sen de farkında olmalısın
genel olarak konuşursak, uzantınız açılmadan önce en az bir kapsam açılmış olacaktır.
yüklendiğinden, eşleşen bir "başlangıç"a sahip olmayan bazı "pre/post_end" çiftlerini göreceksiniz.
incelenmesi iç veri yapılar ile the "çöplük" fonksiyonlar
Hata ayıklamaya yardımcı olmak için kaynak dosya çöplük.c üreten bir dizi fonksiyon içerir.
dahili veri yapılarının biçimlendirilmiş çıktısı.
Bu işlevlerden en yaygın olarak kullanılanı "Perl_sv_dump"; SV'leri boşaltmak için kullanılır,
AV'ler, HV'ler ve CV'ler. "Devel::Peek" modülü, hata ayıklama çıktısı üretmek için "sv_dump" öğesini çağırır
Perl-space'den, bu modülün kullanıcıları zaten formatına aşina olmalıdır.
"Perl_op_dump", bir "OP" yapısını veya türevlerinden herhangi birini boşaltmak için kullanılabilir ve
"Perl -Dx"e benzer çıktılar üretir; aslında, "Perl_dump_eval" ana kökü boşaltacaktır
Değerlendirilmekte olan kodun tam olarak "-Dx" gibi.
Diğer yararlı işlevler, bir "GV"yi bir işlem ağacına dönüştüren "Perl_dump_sub" dur.
Gibi bir paketteki tüm alt rutinlerde "Perl_dump_sub" çağıran "Perl_dump_packsubs"
so: (Neyse ki, bunların hepsi xsub, yani op ağacı yok)
(gdb) Perl_dump_packsubs(PL_defstash) yazdır
ALT nitelikler::bootstrap = (xsub 0x811fedc 0)
ALT EVRENSEL::can = (xsub 0x811f50c 0)
ALT EVRENSEL::isa = (xsub 0x811f304 0)
ALT EVRENSEL::VERSION = (xsub 0x811f7ac 0)
SUB DynaLoader::boot_DynaLoader = (xsub 0x805b188 0)
ve "Perl_dump_all", tüm alt yordamları zulaya ve
ana kök.
Ne kadar çoklu tercümanlar ve eşzamanlılık vardır destekli
Olayın Arka Planı ve PERL_IMPLICIT_CONTEXT
Perl yorumlayıcısı kapalı bir kutu olarak kabul edilebilir: kodunu beslemek için bir API'si vardır veya
aksi takdirde bir şeyler yapmasını sağlar, ancak kendi kullanımı için işlevleri de vardır. Bu bir koku
bir nesneye çok benzer ve birden çok nesneye sahip olabilmeniz için Perl'i oluşturmanın yolları vardır.
yorumlayıcılar, bir yorumlayıcı ya bir C yapısı olarak ya da bir
ipliğe özgü yapı. Bu yapılar tüm bağlamı, o durumun durumunu içerir.
tercüman.
Bir makro, ana Perl yapı türünü kontrol eder: ÇOKLUK. MULTIPLICITY yapısında
tüm yorumlayıcı durumunu paketleyen bir C yapısı. Çokluğu etkinleştirilmiş perls ile,
PERL_IMPLICIT_CONTEXT de normal olarak tanımlanır ve bir
Üç veri yapısını da temsil eden "gizli" ilk argüman. ÇOKLUK yapar
çok iş parçacıklı perls mümkün (makroyla ilgili ithreads iş parçacığı modeliyle
USE_ITHREADS.)
Diğer iki "kapsülleme" makrosu, PERL_GLOBAL_STRUCT ve PERL_GLOBAL_STRUCT_PRIVATE
(ikincisi birinciyi açar ve birincisi ÇOKLUK'u açar.)
PERL_GLOBAL_STRUCT, Perl'in tüm dahili değişkenlerinin tek bir
global struct, struct perl_vars, (globals) &PL_Vars veya PL_VarsPtr olarak erişilebilir veya
işlev Perl_GetVars(). PERL_GLOBAL_STRUCT_PRIVATE bir adım daha ileri gider,
hala tek bir yapı (ayrılmış ana() ya yığından ya da yığından) ama var
ona işaret eden hiçbir global veri sembolü yok. Her iki durumda da küresel yapı olmalıdır
ilk şey olarak başlatıldı ana() kullanma Perl_init_global_struct() ve
uygun şekilde sonra yırtın perl_free() kullanma Perl_free_global_struct(), Bakınız
miniperlmain.c kullanım detayları için Ayrıca kodlamanızda "dVAR" kullanmanız gerekebilir.
bunları kullanırken "genel değişkenleri bildirin". dTHX bunu sizin için yapıyor
otomatik olarak.
Const olmayan verileriniz olup olmadığını görmek için BSD (veya GNU) uyumlu bir "nm" kullanabilirsiniz:
nm libperl.a | grep -v ' [TURtr] '
Bu herhangi bir "D" veya "d" sembolünü (veya muhtemelen "C" veya "c") gösteriyorsa, sabit olmayan verileriniz var demektir.
Kaldırılan "grep" sembolleri aşağıdaki gibidir: "Tt" metin, veya kod, "Rr" okuma-
bir tek (const) veri ve "U" , anılan harici semboller.
Test t/taşıma/libperl.t "libperl.a" üzerinde bu tür bir sembol akıl sağlığı kontrolü yapar.
Geriye dönük uyumluluk nedenleriyle, yalnızca PERL_GLOBAL_STRUCT öğesinin tanımlanması aslında gizlenmez
büyük bir global yapı içindeki tüm semboller: bazı PerlIO_xxx tabloları görünür halde bırakılır. bu
PERL_GLOBAL_STRUCT_PRIVATE daha sonra her şeyi gizler (PERLIO_FUNCS_DECL'nin nasıl kullanıldığını görün).
Bütün bunlar açıkça Perl dahili fonksiyonlarının her iki alt program olması için bir yol gerektirir.
bir tür yapıyı ilk argüman olarak almak veya altyordamlar hiçbir şeyi
ilk argüman. Yorumlayıcıyı oluşturmanın bu iki çok farklı yolunu etkinleştirmek için,
Perl kaynağı (diğer birçok durumda olduğu gibi) makroları yoğun bir şekilde kullanır ve
altyordam adlandırma kuralları.
İlk sorun: Hangi işlevlerin genel API işlevleri olacağına ve hangilerinin olacağına karar vermek
özel. Adları "S_" ile başlayan tüm işlevler özeldir ("gizli" için "S" düşünün veya
"statik"). Diğer tüm işlevler "Perl_" ile başlar, ancak yalnızca bir işlev başladığı için
"Perl_" olması, API'nin bir parçası olduğu anlamına gelmez. (Bkz. "Dahili Fonksiyonlar".)
olmanın en kolay yolu elbette API'nin bir parçası olan bir işlev, girişini perlapi'de bulmaktır. Eğer
perlapi'de var, API'nin bir parçası. Olmazsa ve olması gerektiğini düşünüyorsan
(yani, uzantınız için buna ihtiyacınız var), neden düşündüğünüzü açıklayan perlbug aracılığıyla posta gönderin
olmalı.
İkinci sorun: Aynı altyordam bildirimlerinin ve çağrılarının aynı olması için bir sözdizimi olmalıdır.
bir yapıyı ilk argüman olarak iletebilir veya hiçbir şey iletemez. Bunu çözmek için,
altyordamlar belirli bir şekilde adlandırılır ve bildirilir. İşte tipik bir başlangıç
Perl bağırsaklarında kullanılan statik işlev:
Statik boşluk
S_incline(pTHX_ karakter *s)
STATIC, C'de "statik" hale gelir ve bazı konfigürasyonlarda #tanımlı olmayabilir.
gelecek.
Genel bir işlev (yani, dahili API'nin bir parçası, ancak kullanım için zorunlu olarak onaylanmadı)
uzantılarda) şöyle başlar:
geçersiz
Perl_sv_setiv(pTHX_ SV* dsv, IV sayı)
"pTHX_" bir dizi makrodan biridir (içinde perl.h) ayrıntılarını gizleyen
tercümanın bağlamı. THX, duruma göre "iş parçacığı", "bu" veya "şey" anlamına gelir.
(Ve hayır, George Lucas dahil değil. :-) İlk karakter, bir için 'p' olabilir.
prototip, 'a' için aargüman veya 'd' için dbildirim, yani "pTHX", "aTHX" ve "dTHX" var,
ve onların varyantları.
Perl, PERL_IMPLICIT_CONTEXT ayarlayan seçenekler olmadan oluşturulduğunda, ilki yoktur.
yorumlayıcının bağlamını içeren argüman. pTHX_ makrosunda sondaki alt çizgi
makro genişletmenin bağlam bağımsız değişkeninden sonra virgül gerektiğini belirtir çünkü diğer
Argümanlar onu takip eder. PERL_IMPLICIT_CONTEXT tanımlı değilse, pTHX_ yok sayılır ve
alt program, ekstra argümanı almak için prototip haline getirilmemiştir. makronun formu
ek açık argüman olmadığında sondaki alt çizgi olmadan kullanılır.
Bir çekirdek işlev diğerini çağırdığında bağlamı geçmelidir. Bu normalde aracılığıyla gizlenir
makrolar. "sv_setiv"i düşünün. Bunun gibi bir şeye genişler:
#ifdef PERL_IMPLICIT_CONTEXT
#define sv_setiv(a,b) Perl_sv_setiv(aTHX_ a,b)
/* bunu vararg işlevleri için yapamaz, aşağıya bakın */
#else
#define sv_setiv Perl_sv_setiv
#endif
Bu iyi çalışır ve XS yazarlarının neşeyle yazabileceği anlamına gelir:
sv_setiv(foo, bar);
ve yine de Perl'in derlenmiş olabileceği tüm modlar altında çalışmasını sağlayın.
Bu, varargs işlevleri için o kadar temiz çalışmaz, ancak makrolar,
argüman sayısı önceden bilinir. Bunun yerine ya onları tam olarak hecelememiz gerekiyor,
"aTHX_" ifadesini ilk argüman olarak iletmek (Perl çekirdeği bunu aşağıdaki gibi işlevlerle yapma eğilimindedir:
Perl_warner) veya içerikten bağımsız bir sürüm kullanın.
Perl_warner'ın içerikten bağımsız sürümüne Perl_warner_nocontext adı verilir ve
ekstra argüman. Bunun yerine dTHX yapar; bağlamı iş parçacığı yerel depolamasından almak için.
Uzantıların kaynak uyumluluğunu elde etmesi için "#define warner Perl_warner_nocontext" yaparız.
performans maliyeti. (Bir argümanı iletmek, onu iş parçacığı yerelinden almaktan daha ucuzdur.
depolamak.)
Perl başlıklarına/kaynaklarına göz atarken [pad]THXx'i göz ardı edebilirsiniz. Bunlar kesinlikle
çekirdek içinde kullanın. Uzantıların ve gömücülerin yalnızca [pad]THX'in farkında olması gerekir.
So ne olmuş için dTHR?
"dTHR", eski iş parçacığı modelini desteklemek için Perl 5.005'te tanıtıldı. eski iş parçacığı
model artık bağlam işaretçilerini iletmek için "THX" mekanizmasını kullanıyor, bu nedenle "dTHR"
artık işe yarar. Perl 5.6.0 ve sonraki sürümleri hala geriye dönük kaynak uyumluluğuna sahiptir,
ancak işlem yapılmaması olarak tanımlanmıştır.
Ne kadar do I kullanım herşey Re-Tweet in uzantılar?
Perl, PERL_IMPLICIT_CONTEXT ile oluşturulduğunda, herhangi bir işlevi çağıran uzantılar
Perl API'nin ilk bağlam argümanını bir şekilde iletmesi gerekecek. Asıl olay sensin
Perl oluşturmadığında uzantının hala derleneceği şekilde yazması gerekecek
PERL_IMPLICIT_CONTEXT etkinleştirilmiş olarak oluşturuldu.
Bunu yapmanın üç yolu vardır. Birincisi, kolay ama verimsiz yol, ki bu aynı zamanda
uzantılarla kaynak uyumluluğunu korumak için varsayılan olarak: ne zaman XSUB.h is
#included, aTHX ve aTHX_ makrolarını geri döndürecek bir işlevi çağırmak için yeniden tanımlar.
bağlam. Böylece, şöyle bir şey:
sv_setiv(sv, sayı);
PERL_IMPLICIT_CONTEXT etkin olduğunda uzantınızda şu anlama gelecektir:
Perl_sv_setiv(Perl_get_context(), sv, sayı);
veya bunun için aksi halde:
Perl_sv_setiv(sv, sayı);
Bunu elde etmek için uzantınızda yeni bir şey yapmanız gerekmez; Perl kütüphanesinden beri
sağlar Perl_get_context(), hepsi işe yarayacak.
İkinci, daha verimli yol, Foo.xs'niz için aşağıdaki şablonu kullanmaktır:
#define PERL_NO_GET_CONTEXT /* verimlilik istiyoruz */
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
STATİK void my_private_function(int arg1, int arg2);
Statik boşluk
my_private_function(int argüman1, int argüman2)
{
dTHX; /* bağlamı getir */
... birçok Perl API işlevini çağırın ...
}
[... vb ...]
MODÜL = Foo PAKETİ = Foo
/* tipik XSUB */
geçersiz
my_xsub(arg)
int argüman
KOD:
my_private_function(arg, 10);
Bir uzantı yazmanın normal yolundan yalnızca iki değişikliğin ekleme olduğunu unutmayın.
Perl başlıklarını eklemeden önce bir "#define PERL_NO_GET_CONTEXT" ve ardından bir
"dTHX;" Perl API'sini çağıracak her işlevin başlangıcında bildirim. (Yapacaksın
Hangi işlevlerin buna ihtiyacı olduğunu bilin, çünkü C derleyicisi bir
bu işlevlerde bildirilmemiş tanımlayıcı.) XSUB'lar için herhangi bir değişiklik gerekli değildir.
kendileri, çünkü XS() makro, örtük bağlamda geçmek için doğru bir şekilde tanımlanmışsa
gerekli.
Üçüncü, daha da etkili yol, Perl bağırsaklarında nasıl yapıldığını taklit etmektir:
#define PERL_NO_GET_CONTEXT /* verimlilik istiyoruz */
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
/* pTHX_ yalnızca Perl API'sini çağıran işlevler için gereklidir */
STATİK void my_private_function(pTHX_ int arg1, int arg2);
Statik boşluk
my_private_function(pTHX_ int argüman1, int argüman2)
{
/* dTHX; burada gerekli değildir, çünkü THX bir argümandır */
... Perl API işlevlerini çağırın ...
}
[... vb ...]
MODÜL = Foo PAKETİ = Foo
/* tipik XSUB */
geçersiz
my_xsub(arg)
int argüman
KOD:
my_private_function(aTHX_ argüman, 10);
Bu uygulamanın bir işlev çağrısı kullanarak bağlamı getirmesi gerekmez, çünkü
her zaman ekstra bir argüman olarak iletilir. Basitlik veya verimlilik ihtiyaçlarınıza bağlı olarak,
önceki iki yaklaşımı özgürce karıştırabilirsiniz.
"pTHX" ten sonra asla virgül eklemeyin - her zaman makronun biçimini
açık argümanlar alan fonksiyonlar veya argümansız form için alt çizgi
açık argümanları olmayan işlevler için.
"-DPERL_GLOBAL_STRUCT" ile Perl derleniyorsa, "dVAR" tanımı gereklidir
Perl global değişkenleri (bkz. Perlvars.h or globvar.sym) işlevinde erişilir
ve "dTHX" kullanılmaz ("dTHX", gerekirse "dVAR"ı içerir). Biri fark eder
"dVAR" ihtiyacı yalnızca söz konusu derleme zamanı tanımlamasıyla, aksi takdirde Perl global
değişkenler olduğu gibi görünür.
Şimdi I do bir şey özel if I çağrı perl itibaren çoklu İş Parçacığı?
Bir iş parçacığında tercümanlar yaratır ve sonra onları başka bir iş parçacığında çağırmaya devam ederseniz,
perl'in kendi Thread Local Storage (TLS) yuvasının doğru şekilde başlatıldığından emin olmanız gerekir.
bu iplerin her biri.
"Perl_alloc" ve "perl_clone" API işlevleri, TLS yuvasını otomatik olarak
tercüman oluşturdular, böylece özel bir şey yapmaya gerek kalmazsa
yorumlayıcıya her zaman onu oluşturan aynı iş parçacığından erişilir ve bu iş parçacığı
daha sonra başka tercümanlar oluşturun veya arayın. Eğer durum bu değilse, yapmanız gereken
Perl API'sinde herhangi bir işlevi çağırmadan önce iş parçacığının TLS yuvasını ayarlayın
özel tercüman. Bu, "PERL_SET_CONTEXT" makrosu çağrılarak yapılır.
yaptığınız ilk şey olarak iş parçacığı:
/* bunu some_perl ile başka bir şey yapmadan önce yapın */
PERL_SET_CONTEXT(bazı_perl);
... some_perl'deki diğer Perl API çağrıları buraya gidin ...
gelecek planlar ve PERL_IMPLICIT_SYS
Tıpkı PERL_IMPLICIT_CONTEXT'in yorumlayıcının sunduğu her şeyi bir araya getirmenin bir yolunu sağlaması gibi.
kendisi hakkında bilgi sahibi olur ve onu etrafta dolaştırır, dolayısıyla tercümanın da
üzerinde çalıştığı ortam hakkında bildiği her şeyi bir araya toplar. Bu ile etkinleştirilir
PERL_IMPLICIT_SYS makrosu. Şu anda yalnızca Windows'ta USE_ITHREADS ile çalışır.
Bu, ek bir işaretçi ("ana bilgisayar" ortamı olarak adlandırılır) sağlama becerisine izin verir.
tüm sistem çağrıları. Bu, tüm sistem öğelerinin kendi özelliklerini korumasını mümkün kılar.
kendi durumu, yedi C yapısına bölünmüştür. Bunlar her zamanki gibi ince ambalajlar
sistem çağrıları (bkz. win32/perllib.c) varsayılan Perl yürütülebilir dosyası için, ancak daha fazlası için
hırslı ev sahibi (yapacak olan gibi çatal() öykünme) için gereken tüm ekstra işler
farklı tercümanların aslında farklı "süreçler" olduğunu varsayın, yapılacaktı
.
Perl motoru/yorumlayıcısı ve ana bilgisayar ortogonal varlıklardır. Bir tane olabilir veya
arasında serbest ilişki bulunan bir süreçte daha fazla tercüman ve bir veya daha fazla "ana bilgisayar"
Onları.
İç fonksiyonlar
Perl'in dış dünyaya maruz kalacak tüm dahili işlevleri öneklidir.
XS işlevleriyle veya bir programda kullanılan işlevlerle çakışmamaları için "Perl_" ile
Perl'in gömülü olduğu. Benzer şekilde, tüm global değişkenler "PL_" ile başlar. (İle
kural, statik işlevler "S_" ile başlar.)
Perl çekirdeğinin içinde ("PERL_CORE" tanımlı), fonksiyonlara ya da ile ulaşabilirsiniz.
"Perl_" öneki olmadan, içinde yaşayan bir grup tanım sayesinde gömmek.h. Bunu not et
uzantı kodu değil "PERL_CORE" ayarla; bu, tüm Perl iç öğelerini ortaya çıkarır ve
muhtemelen her yeni Perl sürümünde XS'nin bozulmasına neden olur.
Dosya gömmek.h otomatik olarak oluşturulur embed.pl ve gömmek.fnc. embed.pl Ayrıca
dahili işlevler için prototipleme başlık dosyalarını oluşturur,
belgeler ve diğer birçok parça ve parça. Yeni eklediğinizde önemlidir
çekirdeğe işlev yapın veya mevcut olanı değiştirin, içindeki tablodaki verileri değiştirirsiniz.
gömmek.fnc ilave olarak. İşte o tablodan bir örnek giriş:
Apd |SV** |av_fetch |AV* ar|I32 anahtarı|I32 lval
İkinci sütun dönüş tipi, üçüncü sütun isimdir. Bundan sonra sütunlar
argümanlar. İlk sütun bir dizi bayraktır:
A Bu işlev, genel API'nin bir parçasıdır. Tüm bu işlevler ayrıca 'd'ye sahip olmalıdır,
çok azı yapmaz.
p Bu işlevin bir "Perl_" öneki vardır; yani "Perl_av_fetch" olarak tanımlanmıştır.
d Bu işlevin, "apidoc" özelliğini kullanan belgeleri vardır.
ikinci. Bazı işlevlerde 'd' vardır ancak 'A' yoktur; dokümanlar iyidir.
Diğer mevcut bayraklar:
s Bu statik bir fonksiyondur ve "STATIC S_whatever" olarak tanımlanır ve genellikle
kaynaklarda "whatever(...)" şeklindedir.
n Bunun bir yorumlayıcı bağlamına ihtiyacı yoktur, bu nedenle tanımda "pTHX" yoktur ve
arayanların "aTHX" kullanmadığını izler. (Bkz. "Arka Plan ve PERL_IMPLICIT_CONTEXT".)
r Bu işlev hiçbir zaman geri dönmez; "croak", "çıkış" ve arkadaşlar.
f Bu işlev, "printf" stilinde değişken sayıda argüman alır. argüman listesi
"..." ile bitmeli, şöyle:
Afprd |void |croak |const char* pat|...
M Bu işlev, deneysel geliştirme API'sinin bir parçasıdır ve değişebilir veya kaybolabilir
haber verilmeksizin
o Bu işlev, örneğin "Perl_parse" için tanımlayacak bir uyumluluk makrosuna sahip olmamalıdır.
"ayrıştırma". "Perl_parse" olarak adlandırılmalıdır.
x Bu işlev Perl çekirdeğinden dışa aktarılmaz.
m Bu bir makro olarak uygulanır.
X Bu işlev açıkça dışa aktarılır.
E Bu işlev, Perl çekirdeğinde bulunan uzantılar tarafından görülebilir.
b İkili geriye dönük uyumluluk; bu işlev bir makrodur ancak aynı zamanda bir "Perl_" içerir
uygulama (ihraç edilir).
diğerleri
Diğerleri için "embed.fnc"nin üst kısmındaki yorumlara bakın.
düzenlerseniz embed.pl or gömmek.fnc, zorlamak için "regen_headers yap" komutunu çalıştırmanız gerekecek.
yeniden inşa etmek gömmek.h ve diğer otomatik oluşturulan dosyalar.
Biçimli Baskı of IV'ler, UV'ler, ve NV'ler
yerine IV'ler, UV'ler veya NVS yazdırıyorsanız, stdio(3) gibi stil biçimlendirme kodları
%d, %ld, %f, taşınabilirlik için aşağıdaki makroları kullanmalısınız
IVdf IV ondalık olarak
UVuf UV ondalık olarak
UV of UV sekizli
UVxf UV onaltılı
NVef NV %e-benzeri
NVff NV %f benzeri
NVgf NV %g benzeri
Bunlar 64-bit tamsayılar ve uzun çiftler ile ilgilenecektir. Örneğin:
printf("IV, %"IVdf"\n", iv);
IVdf, IV'ler için doğru format ne olursa olsun genişleyecektir.
Farklı "uzun çiftler" olduğuna dikkat edin: Perl, derleyicide ne varsa onu kullanır.
İşaretçilerin adreslerini yazdırıyorsanız, UVxf ile birlikte kullanın. PTR2UV(), %lx kullanmayın
veya %p.
İşaretçiden Tamsayıya ve Tamsayı-İşaretçi
İşaretçi boyutu mutlaka tamsayı boyutuna eşit olmadığı için aşağıdaki makroları kullanın.
O doğru.
PTR2UV(işaretçi)
PTR2IV(işaretçi)
PTR2NV(işaretçi)
INT2PTR(işaretçi tipi, tamsayı)
Örneğin:
IV IV = ...;
SV *sv = INT2PTR(SV*, iv);
ve
AV *av = ...;
UV uv = PTR2UV(av);
Istisna kullanma
XS modüllerinde çok temel istisna işleme yapmak için birkaç makro vardır. Var
eklemeden önce "NO_XSLOCKS" tanımlamak için XSUB.h bu makroları kullanabilmek için:
#define NO_XSLOCKS
#include "XSUB.h"
Bu makroları, çalabilecek bir kod çağırırsanız kullanabilirsiniz, ancak biraz temizleme yapmanız gerekir.
kontrolü Perl'e geri vermeden önce. Örneğin:
dXCPT; /* gerekli değişkenleri ayarla */
XCPT_TRY_START {
code_that_may_croak();
} XCPT_TRY_END
XCPT_CATCH
{
/* burada temizlik yap */
XCPT_RETHROW;
}
Yakalanan bir istisnayı her zaman yeniden göndermeniz gerektiğini unutmayın. Bunları kullanmak
makrolarda, istisnayı yakalayıp yok saymak mümkün değildir. Eğer zorundaysan
istisnayı yoksayın, "call_*" işlevini kullanmanız gerekir.
Yukarıdaki makroları kullanmanın avantajı, ekstra bir fonksiyon ayarlamanıza gerek olmamasıdır.
"call_*" için ve bu makroları kullanmanın "call_*" kullanmaktan daha hızlı olduğunu.
Kaynak Dökümanlar
Dahili işlevleri belgelemek ve otomatik olarak üretmek için bir çaba var.
onlardan referans kılavuzları -- perlapi, tüm işlevleri ayrıntılandıran böyle bir kılavuzdur.
XS yazarları tarafından kullanılabilir. perlintern, aşağıdakiler için otomatik oluşturulmuş kılavuzdur.
API'nin parçası olmayan ve yalnızca dahili kullanım için olduğu varsayılan işlevler.
Kaynak dokümantasyonu, POD yorumlarını C kaynağına şu şekilde koyarak oluşturulur:
/*
=apidoc sv_setiv için
Verilen SV'ye bir tamsayı kopyalar. 'Ayarlama' büyüsünü işlemez. Görmek
C .
= kes
*/
Perl çekirdeğine işlevler eklerseniz lütfen bazı belgeleri deneyin ve sağlayın.
Geriye uygunluk
Perl API zamanla değişir. Yeni fonksiyonlar eklenir veya mevcut arayüzler
fonksiyonlar değiştirilir. "Devel::PPPort" modülü, uyumluluk kodu sağlamaya çalışır.
bu değişikliklerden bazıları, bu nedenle XS yazarlarının desteklerken kendilerinin kodlaması gerekmez
Perl'in birden çok sürümü.
"Devel::PPPort" bir C başlık dosyası oluşturur ppport.h bu aynı zamanda bir Perl betiği olarak da çalıştırılabilir.
Üretmek ppport.h, koşmak:
perl -MDevel::PPPort -eDevel::PPPort::WriteFile
Komut dosyası, mevcut XS kodunu kontrol etmenin yanı sıra uyumluluğu almak için de kullanılabilir.
"--api-info" komut satırı anahtarını kullanarak çeşitli API çağrıları için bilgi. İçin
örnek:
% Perl ppport.h --api-info=sv_magicext
Ayrıntılar için bkz. "perldoc ppport.h".
Unicode Destek
Perl 5.6.0, Unicode desteğini tanıttı. Taşıyıcıların ve XS yazarlarının
bu desteği anlayın ve yazdıkları kodun Unicode'u bozmadığından emin olun
verileri.
Ne is tek kod, bu arada?
Eski, daha az aydınlanmış zamanlarda hepimiz ASCII kullanırdık. Çoğumuz öyleydi zaten.
ASCII ile ilgili en büyük sorun, Amerikan olmasıdır. Hayır, aslında bu değil
sorun; sorun şu ki, kullanmayan insanlar için özellikle yararlı değil.
Roman alfabesi. Eskiden olan şey, belirli dillerin kendi dillerine yapışmasıydı.
alfabe, sıranın üst aralığında, 128 ile 255 arasında.
tam olarak ASCII olmayan pek çok varyantla sonuçlandı ve bunun bütün amacı
bir standart kayboldu.
Daha da kötüsü, Çince veya Japonca gibi yüzlerce veya
binlerce karakter, o zaman onları gerçekten sadece 256'ya sığdıramazsınız, bu yüzden
ASCII'yi tamamen unutun ve referans için sayı çiftlerini kullanarak kendi sistemlerini kurun.
bir karaktere.
Bunu düzeltmek için, bazı kişiler Unicode, Inc.'i kurdu ve aşağıdakileri içeren yeni bir karakter seti üretti:
aklınıza gelebilecek tüm karakterler ve daha fazlası. birkaç yolu var
bu karakterleri temsil eder ve Perl'in kullandığına UTF-8 denir. UTF-8 kullanır
bir karakteri temsil etmek için değişken bayt sayısı. Unicode hakkında daha fazla bilgi edinebilir ve
Perlunicode'da Perl'in Unicode modeli.
(EBCDIC platformlarında, Perl bunun yerine UTF-8'in bir biçimi olan UTF-EBCDIC'yi kullanır.
EBCDIC platformları. Aşağıda, sadece UTF-8 hakkında konuşuyoruz. UTF-EBCDIC, UTF-8 gibidir, ancak
detaylar farklıdır. Makrolar sizden farkları gizler, sadece şunu unutmayın:
aşağıda sunulan belirli sayılar ve bit desenleri UTF-EBCDIC'de farklılık gösterecektir.)
Ne kadar yapabilmek I tanımak a UTF-8 dize?
Yapamazsın. Bunun nedeni, UTF-8 verilerinin, UTF-8 olmayan veriler gibi bayt cinsinden depolanmasıdır. bu
Unicode karakter 200, (sizin altıgen türleri için 0xC8) büyük harf E, ciddi bir aksanla
iki bayt "v196.172" ile temsil edilir. Ne yazık ki, Unicode olmayan dize
"chr(196).chr(172)" de bu bayt dizisi var. Yani sadece bakarak söyleyemezsiniz --
Unicode girişini ilginç bir problem yapan şey budur.
Genel olarak, neyle uğraştığınızı bilmeniz veya tahmin etmeniz gerekir. bu
API işlevi "is_utf8_string" yardımcı olabilir; bir dize yalnızca geçerli içeriyorsa size söyleyecektir
UTF-8 karakterleri ve geçerli UTF-8 gibi görünen UTF-8 olmayan bir dizenin şansı
artan dize uzunluğu ile çok hızlı bir şekilde çok küçük. Karakter bazında,
"isUTF8_CHAR", bir dizedeki mevcut karakterin geçerli UTF-8 olup olmadığını size söyleyecektir.
Ne kadar yok UTF-8 temsil etmek Unicode karakterleri?
Yukarıda bahsedildiği gibi, UTF-8, bir karakteri depolamak için değişken sayıda bayt kullanır.
0...127 değerlerine sahip karakterler, tıpkı iyi ol' ASCII gibi bir bayt içinde saklanır.
128 karakteri "v194.128" olarak saklanır; bu, karakter 191'e kadar devam eder;
"v194.191". Artık bitlerimiz bitti (191 ikili 10111111'dir) bu yüzden devam ediyoruz; karakter
192 "v195.128"dir. Ve böylece 2048 karakterinde üç bayta taşınarak devam eder. "Unicode
Perlunicode'daki Encodings", bunun nasıl çalıştığına dair resimlere sahiptir.
Bir UTF-8 dizesiyle uğraştığınızı bildiğinizi varsayarsak, ilkinin ne kadar süreceğini öğrenebilirsiniz.
içindeki karakter "UTF8SKIP" makrosu ile:
char *utf = "\305\233\340\240\201";
I32 uzunluk;
len = UTF8SKIP(utf); /* burada uzunluk 2'dir */
utf += uzunluk;
len = UTF8SKIP(utf); /* burada uzunluk 3'dir */
UTF-8 dizesindeki karakterleri atlamanın başka bir yolu da "utf8_hop" kullanmaktır.
dize ve atlanacak bir dizi karakter. Sınır kontrolü konusunda tek başınasın,
Yine de, hafifçe kullanmayın.
Çok baytlı bir UTF-8 karakterindeki tüm baytlar, yüksek bit kümesine sahip olacaktır, böylece
bu karakterle bunun gibi özel bir şey yapmanız gerekiyor ("UTF8_IS_INVARIANT()"
baytın UTF-8'de bile tek bir bayt olarak kodlanıp kodlanmadığını test eden bir makrodur):
U8 *utf;
U8 *utf_end; /* 1 utf ile gösterilen arabelleğin ötesinde */
UV UV; /* Not: UV, U8 değil, karakter değil */
STRLEN len; /* bayt cinsinden karakter uzunluğu */
eğer (!UTF8_IS_INVARIANT(*utf))
/* Bunu UTF-8 olarak ele almalı */
uv = utf8_to_uvchr_buf(utf, utf_end, &len);
başka
/* Bu karakteri bir bayt olarak ele al */
uv = *utf;
Bu örnekte, "utf8_to_uvchr_buf" değerini almak için kullandığımızı da görebilirsiniz.
karakter; "uvchr_to_utf8" ters işlevi, bir UV'yi UTF-8'e yerleştirmek için kullanılabilir:
eğer (!UVCHR_IS_INVARIANT(uv))
/* Bunu UTF8 olarak ele almalı */
utf8 = uvchr_to_utf8(utf8, uv);
başka
/* Bu karakteri bir bayt olarak ele al */
*utf8++ = uv;
Sen , eğer mülteci statüleri sona erdirilmemişse Amerika'ya geldikten bir yıl sonra bir durumdaysanız, yukarıdaki işlevleri kullanarak karakterleri UV'ye dönüştürün
UTF-8 ve UTF-8 olmayan karakterlerle eşleşmeniz gereken yer. UTF-8'i atlayamazsınız
Bu durumda karakterler. Bunu yaparsanız, hi-bit eşleştirme yeteneğini kaybedersiniz.
UTF-8 olmayan karakterler; örneğin, UTF-8 dizginiz "v196.172" içeriyorsa ve atlarsanız
o karakterle asla eşleşemezsin"chr(200)" UTF-8 olmayan bir dizgede. Öyleyse bunu yapma!
(Yukarıdaki örneklerde değişmez karakterleri test etmemiz gerekmediğine dikkat edin.
işlevler, iyi biçimlendirilmiş herhangi bir UTF-8 girişinde çalışır. Sadece bundan kaçınmak daha hızlı
gerekli olmadığında ek yük işlevi görür.)
Ne kadar yok Perl mağaza UTF-8 Teller?
Şu anda Perl, UTF-8 dizeleri ve UTF-8 olmayan dizelerle biraz farklı şekilde ilgilenmektedir. A
SV'deki "SVf_UTF8" bayrağı, dizenin dahili olarak UTF-8 olarak kodlandığını gösterir.
Onsuz, bayt değeri kod noktası numarasıdır ve bunun tersi de geçerlidir. Bu bayrak sadece
SV "SvPOK" ise veya "SvPV" veya bir
benzer makro. Bu bayrağı aşağıdaki makrolarla kontrol edebilir ve değiştirebilirsiniz:
SvUTF8(sv)
SvUTF8_on(sv)
SvUTF8_off(sv)
Bu bayrağın Perl'in dizgiyi ele alışı üzerinde önemli bir etkisi vardır: eğer UTF-8 verisi değilse
uygun şekilde ayırt edilmiş, düzenli ifadeler, "uzunluk", "altstr" ve diğer dize işlemleri
işlemler istenmeyen (yanlış) sonuçlar doğuracaktır.
Sorun, örneğin UTF-8 olarak işaretlenmemiş bir dizeniz olduğunda ortaya çıkar ve
UTF-8 olabilecek bir bayt dizisi içerir -- özellikle UTF-8 olmayan ve
UTF-8 dizeleri.
"SVf_UTF8" bayrağının PV değerinden ayrı olduğunu asla unutmayın; emin olmalısın
SV'leri manipüle ederken yanlışlıkla kapatmazsınız. Daha spesifik olarak, sen
bunu yapmayı bekleyemez:
SV *sv;
SV *nsv;
STRLEN len;
karakter *p;
p = SvPV(sv, uzunluk);
fronicate(p);
nsv = newSVpvn(p, uzun);
"char*" dizesi size tüm hikayeyi anlatmaz ve bir
SV, yalnızca dize değerini kopyalayarak. Eski SV'nin UTF8 bayrağına sahip olup olmadığını kontrol edin (sonra the
"SvPV" çağrısı) ve buna göre hareket edin:
p = SvPV(sv, uzunluk);
is_utf8 = SvUTF8(sv);
frobnicate(p, is_utf8);
nsv = newSVpvn(p, uzun);
eğer (is_utf8)
SvUTF8_on(nsv);
Yukarıda, "frobnicate" işleviniz değiştirilip değiştirilmediğinin farkında olunması için değiştirilmiştir.
UTF-8 verileriyle ilgilenmiyor, böylece dizeyi uygun şekilde işleyebilir.
Sadece bir SV'yi bir XS işlevine geçirmek ve SV'nin verilerini kopyalamak yeterli olmadığı için
UTF8 bayraklarını kopyalayın, daha az doğru bir XS işlevine bir "char *" geçirmektir.
Tam genellik için, bir SV'deki dizenin doğru olup olmadığını görmek için perlapi makrosunda "DO_UTF8" kullanın.
olduğu tedavi UTF-8 olarak. Bu, XS işlevine yapılan çağrının yapılıp yapılmadığını hesaba katar.
"kullanım baytları" kapsamında yapılmıştır. Eğer öyleyse, aşağıdakileri oluşturan temeldeki baytlar
UTF-8 dizesi, temsil ettikleri karakterden ziyade açığa çıkarılacaktır. Ama bu pragma
yalnızca gerçekten hata ayıklama ve belki de bayt düzeyinde düşük seviyeli testler için kullanılmalıdır.
Bu nedenle, çoğu XS kodunun bununla ilgilenmesine gerek yoktur, ancak perl çekirdeğinin çeşitli alanlarıyla ilgilenmesi gerekir.
desteklemek gerekiyor.
Ve bu hikayenin tamamı değil. Perl v5.12'den başlayarak, kodlanmamış dizeler
UTF-8, çeşitli koşullar altında Unicode olarak da değerlendirilebilir (bkz.
Perlunicode'da "Unicode Kuralları"). Bu, yalnızca
sıra sayıları 128 ile 255 arasındadır ve davranışları ASCII'ye göre Unicode'a göre değişir
kurallar, kodunuzun önemsediği şekillerde (perlunicode'da "Unicode Hatası"na bakın). Orası
Bununla başa çıkmak için yayınlanmış bir API yoktur, çünkü değişebilir, ancak şuna bakabilirsiniz:
içindeki "pp_lc" kodu ppc şu anda nasıl yapıldığına dair bir örnek için.
Ne kadar do I dönüştürmek a dizi için UTF-8 mi?
UTF-8 ve UTF-8 olmayan dizeleri karıştırıyorsanız, UTF-8 olmayan dizeleri yükseltmek gerekir
UTF-8'e dizeler. Bir SV'niz varsa, bunu yapmanın en kolay yolu şudur:
sv_utf8_upgrade(sv);
Ancak, bunu yapmamalısınız, örneğin:
if (!SvUTF8(sol))
sv_utf8_upgrade(sol);
Bunu bir ikili operatörde yaparsanız, aslında gelen dizelerden birini değiştireceksiniz.
operatöre girer ve son kullanıcı tarafından fark edilmemesi gerekirken,
eksik koddaki sorunlar.
Bunun yerine, "bytes_to_utf8" size UTF-8 kodlu bir kopya onun string argümanı. Bu
verilere zarar vermeden karşılaştırmalar vb. için kullanılabilir olması için yararlıdır.
orijinal SV. Diğer yöne gitmek için "utf8_to_bytes" da var, ancak doğal olarak bu
dize, tek bir karakterde temsil edilemeyen 255'in üzerinde herhangi bir karakter içeriyorsa başarısız olur
bayt.
Ne kadar do I karşılaştırmak Teller?
perlapi'de "sv_cmp" ve perlapi'de "sv_cmp_flags" iki SV'nin sözlüksel karşılaştırmasını yapar,
ve UTF-8ness'i düzgün bir şekilde ele alın. Bununla birlikte, Unicode'un çok daha meraklısı belirttiğini unutmayın.
Unicode::Collate modülü aracılığıyla sağlanan harmanlama mekanizması.
İki diziyi eşitlik/eşitsizlik açısından karşılaştırmak için sadece "memEQ()" ve
"memNE()" her zamanki gibi, ancak dizelerin hem UTF-8 hem de UTF-8 kodlu olmaması gerekir.
İki dizgiyi büyük/küçük harf duyarlı olmadan karşılaştırmak için "foldEQ_utf8()" kullanın (dizelerin
aynı UTF-8ness'e sahip).
Is Orada bir şey başka I gerek için biliyor musunuz?
Pek sayılmaz. Sadece şunları hatırla:
· Bir "char *" veya "U8 *" dizesinin UTF-8 olup olmadığını anlamanın bir yolu yoktur. Ama sen yapabilirsin
bir SV'nin, dizgeleştirmeden sonra "DO_UTF8" öğesini çağırarak UTF-8 olarak ele alınıp alınmayacağını söyleyin
"SvPV" veya benzer bir makro ile. Ve SV'nin gerçekten UTF-8 olup olmadığını anlayabilirsiniz (hatta
"SvUTF8" bayrağına bakarak (tekrar sonra
onu dizmek). Bir şeyin UTF-8 olması gerekiyorsa bayrağı ayarlamayı unutmayın. Davranmak
PV'nin bir parçası olarak bayrak, olmasa da -- PV'yi bir yere iletirseniz,
bayrağını da geçir.
· Bir dize UTF-8 ise, her zaman değere ulaşmak için "utf8_to_uvchr_buf" kullanın, aksi takdirde
"UTF8_IS_INVARIANT(*s)" bu durumda *s kullanabilirsiniz.
· UTF-8 dizisine bir karakter UV yazarken, her zaman sürece "uvchr_to_utf8" kullanın
"UVCHR_IS_INVARIANT(uv))" bu durumda "*s = uv" kullanabilirsiniz.
· UTF-8 ve UTF-8 olmayan dizeleri karıştırmak zordur. Yeni bir dize almak için "bytes_to_utf8" kullanın
UTF-8 kodlu olan ve ardından bunları birleştirin.
görenek Operatörler
Özel operatör desteği, kendi operasyonlarınızı tanımlamanıza izin veren deneysel bir özelliktir.
Bu, öncelikle Perl'deki diğer diller için tercümanların oluşturulmasına izin vermek içindir.
çekirdek, ancak aynı zamanda "makro işlemler" (işlemler) oluşturulması yoluyla optimizasyonlara da izin verir.
"gvsv,
gvsv, ekleyin".)
Bu özellik, yeni bir işlem türü olan "OP_CUSTOM" olarak uygulanmaktadır. Perl çekirdeği "bilmiyor"
bu operasyon türü hakkında özel bir şey yok ve bu nedenle herhangi bir optimizasyona dahil olmayacak.
Bu aynı zamanda özel operasyonlarınızı herhangi bir operasyon yapısı olarak tanımlayabileceğiniz anlamına gelir -- tekli,
ikili, liste ve benzeri -- beğenirsiniz.
Özel operatörlerin sizin için ne yapmayacağını bilmek önemlidir. Yeni eklemene izin vermiyorlar
doğrudan Perl'e sözdizimi. Doğrudan yeni anahtar kelimeler eklemenize bile izin vermezler. Aslında,
Perl'in bir programı derleme şeklini hiç değiştirmezler. Bu değişiklikleri yapmak zorundasın
Perl programı derledikten sonra kendiniz. Bunu, işlemi manipüle ederek yaparsınız.
"CHECK" bloğu ve "B::Generate" modülünü kullanarak veya özel bir gözetleme deliği ekleyerek ağaç
"optimize" modülü ile optimize edici.
Bunu yaptığınızda, normal Perl operasyonlarını özel operasyonlar ile değiştirerek operasyonları özel operasyonlarla değiştirirsiniz.
kendi PP işlevinizin "OP_CUSTOM" ve "op_ppaddr" yazın. Bu tanımlanmalıdır
XS kodudur ve "pp_*.c" içindeki PP operasyonları gibi görünmelidir. sağlamaktan siz sorumlusunuz.
operasyonunuzun yığından uygun sayıda değer aldığını ve siz
gerekirse yığın işaretleri eklemekten sorumludur.
Ayrıca, operasyonunuzu Perl yorumlayıcısına "kaydetmelisiniz", böylece üretebilir.
mantıklı hata ve uyarı mesajları. Birden fazla özel operasyona sahip olmak mümkün olduğundan
Bir "mantıksal" işlem türü "OP_CUSTOM" içinde, Perl "o->op_ppaddr" değerini kullanır.
hangi özel operasyonla uğraştığını belirleyin. için bir "XOP" yapısı oluşturmalısınız.
kullandığınız her ppaddr, özel operasyonun özelliklerini "XopENTRY_set" ile ayarlayın ve kayıt olun
"Perl_custom_op_register" kullanarak ppaddr'ye karşı yapı. önemsiz bir örnek olabilir
gibi görünmek:
statik XOP my_xop;
statik OP *my_pp(pTHX);
BOT:
XopENTRY_set(&my_xop, xop_name, "myxop");
XopENTRY_set(&my_xop, xop_desc, "Yararsız özel işlem");
Perl_custom_op_register(aTHX_ my_pp, &my_xop);
Yapıdaki kullanılabilir alanlar şunlardır:
xop_adı
Operasyonunuz için kısa bir isim. Bu, bazı hata mesajlarına dahil edilecek ve ayrıca
B modülü tarafından "$op->name" olarak döndürülür, bu nedenle modülün çıktısında görünecektir
B::Özlü gibi.
xop_desc
Operasyonun işlevinin kısa bir açıklaması.
xop_class
Bu operasyonun kullandığı çeşitli *OP yapılarından hangisini. Bu, "OA_*" öğelerinden biri olmalıdır
sabitler operasyon h, yani
OA_BASEOP
OA_UNOP
OA_BINOP
OA_LOGOP
OA_LISTOP
OA_PMOP
OA_SVOP
OA_PADOP
OA_PVOP_OR_SVOP
Bu sadece "PVOP" olarak yorumlanmalıdır. "_OR_SVOP", yalnızca
çekirdek "PVOP", "OP_TRANS", bazen bunun yerine bir "SVOP" olabilir.
OA_DÖNGÜ
OA_COP
Diğer "OA_*" sabitleri kullanılmamalıdır.
xop_peep
Bu üye "void (*Perl_cpeep_t)(aTHX_ OP)" olarak genişleyen "Perl_cpeep_t" türündedir.
*o, OP *oldop)". Eğer ayarlanırsa, bu fonksiyon "Perl_rpeep" den çağrılır.
Bu tür işlemlere gözetleme deliği optimize edici tarafından rastlanır. o ihtiyacı olan OP
optimize etme; eski püskü "op_next" işaret eden önceki OP optimize edilmiştir o.
"B::Generate", özel operasyonların ada göre oluşturulmasını doğrudan destekler.
YAZARLAR
Mayıs 1997'ye kadar bu belge Jeff Okamoto tarafından muhafaza edildi.[e-posta korumalı]>. Bu
şimdi Perl 5 Porters tarafından Perl'in bir parçası olarak korunur[e-posta korumalı]>.
Dean Roehrich, Malcolm Beattie, Andreas Koenig'den çok sayıda yardım ve öneriyle,
Paul Hudson, Ilya Zakharevich, Paul Marquess, Neil Bowers, Matthew Green, Tim Bunce,
Spider Boardman, Ulrich Pfeifer, Stephen McCamant ve Gurusamy Sarathy.
onworks.net hizmetlerini kullanarak perlguts çevrimiçi kullanın