これは、Ubuntu Online、Fedora Online、Windows オンライン エミュレーター、または MAC OS オンライン エミュレーターなどの複数の無料オンライン ワークステーションの XNUMX つを使用して、OnWorks 無料ホスティング プロバイダーで実行できるコマンド perlguts です。
プログラム:
NAME
perlguts-PerlAPIの概要
DESCRIPTION
このドキュメントでは、Perl API の使用方法を説明し、いくつかの方法を提供します。
Perl コアの基本的な仕組みに関する情報。 完成にはほど遠いですが、おそらく
多くの誤りが含まれています。 ご質問やご意見がございましたら、以下の著者までお問い合わせください。
Variables
データ型
Perl には、Perl の XNUMX つの主要なデータ型を処理する XNUMX つの typedef があります。
SV スカラー値
AV 配列値
HV ハッシュ値
各 typedef には、さまざまなデータ型を操作する特定のルーチンがあります。
この試験は is an 「Ⅳ」?
Perl は、次のことが保証されている単純な符号付き整数型である特別な typedef IV を使用します。
ポインター (および整数) を保持するのに十分な大きさである必要があります。 さらに、紫外線もあるので、
これは単に署名されていない IV です。
Perl は、I32 と I16 という 32 つの特別な typedef も使用します。これらは常に少なくとも XNUMX ビットになります。
それぞれ 16 ビット長です。 (繰り返しになりますが、U32 と U16 もあります。)
通常は正確に 32 ビットと 16 ビットの長さですが、Crays では両方とも 64 ビットになります。
ワーキング SV
SV は XNUMX つのコマンドで作成およびロードできます。 設定できる値は XNUMX 種類あります。
ロードされる値: 整数値 (IV)、符号なし整数値 (UV)、double (NV)、文字列
(PV)、および別のスカラー (SV)。 (「PV」は「Pointer Value」の略です。
は文字列のみを指していると説明されているため、名前が間違っています。 ただし、可能です
他のものを指すようにするためです。 たとえば、UV の配列を指すことができます。 しかし、
文字列以外にこれを使用する場合は注意が必要です。
内部的には、PV は文字列のみを対象としています。 たとえば、末尾の「NUL」は次のようになります。
自動的に貼り付けられます。 文字列以外の使用については、この段落でのみ説明します)。
XNUMX つのルーチンは次のとおりです。
SV* newSViv(IV);
SV* newSVuv(UV);
SV* newSVnv(double);
SV* newSVpv(const char*, STRLEN);
SV* newSVpvn(const char*, STRLEN);
SV* newSVpvf(const char*, ...);
SV* newSVsv(SV*);
「STRLEN」は整数型 (Size_t、通常は size_t として定義されます) config.h) を保証
Perl が処理できる文字列のサイズを表すのに十分な大きさである必要があります。
まれですが、より複雑な初期化が必要な SV が発生した場合は、
newSV(len) を含む空の SV。 「len」が 0 の場合は NULL 型の空の SV が返され、それ以外の場合は SV が返されます。
PV 型の場合は、len + 1 (「NUL」の場合) バイトの割り当てられた、アクセス可能なストレージが返されます。
SvPVX経由。 どちらの場合も、SV には undef 値が含まれます。
SV *sv = 新しいSV(0); /* ストレージが割り当てられていません */
SV *sv = 新しいSV(10); /* 10 (+1) バイトの初期化されていないストレージ
* 割り当てられています */
の値を変更するには すでに存在する SV、ルーチンは XNUMX つあります。
void sv_setiv(SV*, IV);
void sv_setuv(SV*, UV);
void sv_setnv(SV*, double);
void sv_setpv(SV*, const char*);
void sv_setpvn(SV*, const char*, STRLEN)
void sv_setpvf(SV*, const char*, ...);
void sv_vsetpvfn(SV*, const char*, STRLEN, va_list *,
SV **、I32、ブール値 *);
void sv_setsv(SV*, SV*);
を使用して、割り当てる文字列の長さを指定できることに注意してください。
「sv_setpvn」、「newSVpvn」、または「newSVpv」、または Perl が次のように長さを計算できるようにすることもできます。
「sv_setpv」を使用するか、「newSVpv」の 0 番目の引数として XNUMX を指定します。 注意してください、
ただし、Perl は「strlen」を使用して文字列の長さを決定します。
「NUL」文字で終わる文字列であり、それ以外の場合は NUL を含みません。
「sv_setpvf」の引数は「sprintf」と同様に処理され、フォーマットされた出力が
という値になります。
「sv_vsetpvfn」は「vsprintf」に似ていますが、ポインタを指定できます。
可変引数リスト、または SV の配列のアドレスと長さに変換します。 最後
引数はブール値を指します。 戻り時に、そのブール値が true の場合、ロケール固有の
情報は文字列のフォーマットに使用されているため、文字列の内容は次のようになります。
信頼できません (perlsec を参照)。 情報がそうでない場合、このポインタは NULL になる可能性があります。
重要。 この関数ではフォーマットの長さを指定する必要があることに注意してください。
「sv_set*()」関数は、「魔法」を持つ値を操作できるほど汎用的ではありません。
このドキュメントの後半の「Magic Virtual Tables」を参照してください。
文字列を含むすべての SV は、「NUL」文字で終了する必要があります。 そうでない場合
「NUL」で終了すると、コア ダンプが発生したり、
「NUL」で終わる文字列を予期する C 関数またはシステム コールへの文字列。 Perl 独自の
この理由により、関数は通常、末尾に「NUL」を追加します。 それにもかかわらず、あなたはそうすべきです
SV に格納されている文字列を C 関数またはシステム コールに渡すときは、十分に注意してください。
SV が指す実際の値にアクセスするには、次のマクロを使用できます。
SvIV(SV*)
SvUV(SV*)
SvNV(SV*)
SvPV(SV*, STRLEN レン)
SvPV_nolen(SV*)
これにより、実際のスカラー型が IV、UV、double、または string に自動的に強制されます。
「SvPV」マクロでは、返された文字列の長さが変数「len」に格納されます。
(これはマクロなので、 &len を使用します)。 データの長さを気にしない場合
つまり、「SvPV_nolen」マクロを使用します。 歴史的には、グローバル変数を使用した「SvPV」マクロ
この場合は「PL_na」が使用されています。 しかし、それは非常に非効率的になる可能性があります。
スレッド化された Perl のスレッドローカル ストレージにアクセスする必要があります。 いずれにせよ、覚えておいてください
Perl では、NUL を含む場合とそうでない場合の両方のデータの任意の文字列を許可します。
「NUL」で終了します。
また、C では「foo(SvPV(s, len), len);」と安全に言うことができないことにも注意してください。 かもしれない
コンパイラでは動作しますが、誰でも動作するわけではありません。 この種の発言は打ち砕いてください
別々の割り当てに分割します。
SV *s;
STRLENレン。
char *ptr;
ptr = SvPV(s, len);
foo(ptr, len);
スカラー値が TRUE かどうかを知りたい場合は、次を使用できます。
SvTRUE(SV*)
Perl は自動的に文字列を拡張しますが、Perl に強制的に文字列を拡張する必要がある場合は、
SV にさらに多くのメモリを割り当てるには、マクロを使用できます。
SvGROW(SV*, STRLEN ニューレン)
これにより、さらにメモリを割り当てる必要があるかどうかが決まります。 そうであれば、それは
関数「sv_grow」。 「SvGROW」は、割り当てられた容量を増やすことのみができ、減らすことはできないことに注意してください。
SV のメモリと、末尾の「NUL」バイト用のスペースが自動的に追加されないこと
(perl 独自の文字列関数は通常、「SvGROW(sv, len + 1)」を実行します)。
既存の SV のバッファに書き込み、その値を文字列に設定する場合は、次を使用します。
SvPV_force() またはそのバリアントの XNUMX つを使用して、SV を強制的に PV にします。 これにより、次のいずれかが削除されます
SV の内容を維持しながら、SV からさまざまな種類の非文字列性を取得します。
PV。 これは、たとえば API 関数からのデータをバッファに追加するために使用できます。
余分なコピーなしで:
(void)SvPVbyte_force(sv, len);
s = SvGROW(sv, len + ニードルン + 1);
/* s+len でニードルンバイトまでを変更するものですが、
newlen バイトを変更します
例えば。 newlen = read(fd, s + len, needlen);
これらの例ではエラーを無視します
*/
s[len + newlen] = '\0';
SvCUR_set(sv, len + newlen);
SvUTF8_off(sv);
SvSETMAGIC(sv);
すでにデータがメモリ内にある場合、またはコードを単純に保ちたい場合は、次のことができます。
次のような sv_cat*() バリアントの XNUMX つを使用します。 sv_catpvn()。 どこかに挿入したい場合は、
使用できる文字列 sv_insert() or sv_insert_flags().
SV の既存のコンテンツが必要ない場合は、次のようにして一部のコピーを回避できます。
sv_setpvn(sv, "", 0);
s = SvGROW(sv, ニードルン + 1);
/* s でニードルンバイトまでを変更するものですが、
新しいバイト
例えば。 newlen = read(fd, s.needlen);
*/
s[newlen] = '\0';
SvCUR_set(sv, newlen);
SvPOK_only(sv); /* SVf_UTF8 もクリアします */
SvSETMAGIC(sv);
繰り返しますが、既にメモリ内にデータがある場合、またはメモリの複雑さを避けたい場合は、
上記では、使用できます sv_setpvn().
バッファが割り当てられている場合 新しい() それをSVの値として設定したい場合は、次のようにできます。
つかいます sv_usepvn_flags()。 Perl の再割り当てを避けたい場合は、いくつかの要件があります。
末尾の NUL に適合するバッファ:
Newx(buf, somesize+1, char);
/* ... バッファを埋める ... */
buf[somesize] = '\0';
sv_usepvn_flags(sv, buf, somesize, SV_SMAGIC | SV_HAS_TRAILING_NUL);
/* buf は現在 perl に属しているため、解放しないでください */
SV があり、Perl がその中にどのような種類のデータが保存されていると考えているかを知りたい場合は、次のようにすることができます。
次のマクロを使用して、SV のタイプを確認してください。
SvIOK(SV*)
SvNOK(SV*)
SvPOK(SV*)
次のコマンドを使用して、SV に格納されている文字列の現在の長さを取得および設定できます。
マクロ:
SvCUR(SV*)
SvCUR_set(SV*, I32 val)
マクロを使用して、SV に格納されている文字列の末尾へのポインターを取得することもできます。
SvEND(SV*)
ただし、これらの最後の XNUMX つのマクロは、「SvPOK()」が true の場合にのみ有効であることに注意してください。
「SV*」に格納されている文字列の末尾に何かを追加したい場合は、
次の機能:
void sv_catpv(SV*, const char*);
void sv_catpvn(SV*, const char*, STRLEN);
void sv_catpvf(SV*, const char*, ...);
void sv_vcatpvfn(SV*, const char*, STRLEN, va_list *, SV **,
I32、ブール値);
void sv_catsv(SV*, SV*);
最初の関数は、「strlen」を使用して追加される文字列の長さを計算します。
XNUMX つ目では、文字列の長さを自分で指定します。 XNUMXつ目の機能
引数を「sprintf」のように処理し、フォーマットされた出力を追加します。 第XNUMX
関数は「vsprintf」と同じように機能します。 SV の配列のアドレスと長さを指定できます。
va_list 引数の代わりに。 XNUMX 番目の関数は、
最初の SV と XNUMX 番目の SV に格納されている文字列。 また、XNUMX 番目の SV も強制的に次のようになります。
文字列として解釈されます。
「sv_cat*()」関数は、「魔法」を持つ値を操作できるほど汎用的ではありません。
このドキュメントの後半の「Magic Virtual Tables」を参照してください。
スカラー変数の名前がわかっている場合は、次のコマンドを使用してその SV へのポインターを取得できます。
次のとおりです。
SV* get_sv("パッケージ::変数名", 0);
変数が存在しない場合は NULL を返します。
この変数 (または他の SV) が実際に「定義」されているかどうかを知りたい場合は、次のようにすることができます。
コール:
SvOK(SV*)
スカラー「undef」値は、「PL_sv_undef」という SV インスタンスに保存されます。
そのアドレスは、「SV*」が必要なときにいつでも使用できます。 しようとしないように注意してください
ランダムな SV を &PL_sv_undef と比較します。 たとえば、Perl コードをインターフェイスする場合、それは機能します。
正しくは:
foo(undef);
ただし、次のように呼び出すと機能しません。
$x = undef;
foo($x);
したがって、繰り返すには常に使用します SvOK() sv が定義されているかどうかを確認します。
また、AV または HV の値として &PL_sv_undef を使用する場合にも注意が必要です (「AV、
HV と未定義の値」)。
「PL_sv_yes」と「PL_sv_no」の XNUMX つの値もあり、ブール値 TRUE と PL_sv_no が含まれます。
それぞれ FALSE 値。 「PL_sv_undef」と同様に、そのアドレスはいつでも使用できます。
「SV*」が必要です。
「(SV *) 0」が &PL_sv_undef と同じであるとは考えないようにしてください。 これを取る
コード:
SV* sv = (SV*) 0;
if (私は実数値を返すつもりです) {
sv = sv_2mortal(新しいSViv(42));
}
sv_setsv(ST(0)、SV);
このコードは、新しい SV (値 42 を含む) を返す必要がある場合に、それを返そうとします。
実数値、それ以外の場合は undef。 代わりに、NULL ポインタが返されました。
最終的には、セグメンテーション違反、バス エラー、または単に奇妙な結果が発生する可能性があります。
最初の行のゼロを &PL_sv_undef に変更すると、すべてがうまくいきます。
作成した SV を解放するには、「SvREFCNT_dec(SV*)」を呼び出します。 通常、この呼び出しは行われません。
必要です(「参照数と死亡率」を参照)。
オフセット
Perlには効率よく先頭から文字を削除する関数「sv_chop」が用意されています
文字列の; SV と PV 内のどこかへのポインタを与えると、それは破棄されます。
ポインターの前のすべて。 効率はちょっとしたハックによって実現します。
実際に文字を削除すると、「sv_chop」はフラグ「OOK」(オフセット OK)を設定して信号を送ります。
オフセット ハックが有効である他の機能、および PV ポインター (と呼ばれる) を移動します。
「SvPVX」)切り捨てられたバイト数だけ前方に転送し、「SvCUR」と「SvLEN」を調整します
それに応じて。 (古い PV ポインターと新しい PV ポインターの間のスペースの一部は、
切り取られたバイト数。)
したがって、この時点では、割り当てたバッファの先頭は「SvPVX(sv) -
SvIV(sv)" がメモリ内にあり、PV ポインタはこの割り当てられた領域の中央を指しています。
ストレージ。
これは例によって最もよく示されます。 通常、コピーオンライトは、
このハックを使用して演算子から置換しますが、その文字列を作成できれば、
コピーオンライトは不可能ですが、プレイ中に確認できます。 現在の実装では、
文字列バッファの最後のバイトは、コピーオンライトの参照カウントとして使用されます。 バッファーの場合
サイズが十分でない場合、コピーオンライトはスキップされます。 まず空の文字列を見てください。
% ./perl -Ilib -MDevel::Peek -le '$a=""; $a .= ""; $a'をダンプします
SV = PV(0x7ffb7c008a70) at 0x7ffb7c030390
REFCNT = 1
フラグ = (POK,pPOK)
PV = 0x7ffb7bc05b50 ""\0
カーソル = 0
レンズ = 10
ここで LEN が 10 であることに注意してください。(プラットフォームによって異なる場合があります)。
文字列を 10 未満の XNUMX に変換し、置換を実行します。
% ./perl -Ilib -MDevel::Peek -le '$a=""; $a.="123456789"; $a=~s/.//; ダンプ($a)'
SV = PV(0x7ffa04008a70) at 0x7ffa04030390
REFCNT = 1
フラグ = (POK,OOK,pPOK)
オフセット= 1
PV = 0x7ffa03c05b61 ( "\1" . ) "23456789"\0
カーソル = 8
レンズ = 9
ここでは、切り取られたバイト数 (1) が OFFSET として次に表示されます。 の部分は、
「本物」と「偽」の始まりの間の文字列は括弧内に示されており、
「SvCUR」と「SvLEN」の値は、本物の始まりではなく、偽の始まりを反映しています。 (最初
ここでは、文字列バッファの文字がたまたま「1」ではなく「\1」に変更されています。
現在の実装では、オフセット カウントを文字列バッファに保存します。 これの対象となるのは、
変化。)
オフセットハックと同様のことがAVで実行され、効率的なシフトと
配列の先頭を切り取る。 一方、「AvARRAY」は次の最初の要素を指します。
Perl から見える配列、「AvALLOC」は C 配列の実際の先頭を指します。
これらは通常同じですが、「シフト」操作は、値を大きくすることで実行できます。
「AvARRAY」を XNUMX つ増やし、「AvFILL」と「AvMAX」を減らします。 もう一度言いますが、実際の場所は、
C 配列の先頭は、配列を解放するときにのみ機能します。 「av_shift」を参照してください。 av.c.
何 本当に ストアド in an SV?
所有しているスカラーのタイプを決定する通常の方法は、「Sv*OK」を使用することであることを思い出してください。
マクロ。 スカラーは数値と文字列の両方になる可能性があるため、通常、これらのマクロは次のようになります。
常に TRUE を返し、「Sv*V」マクロを呼び出すと適切な変換が行われます。
文字列から整数/倍精度、または整数/倍精度から文字列。
もしあなた 本当に SV に整数、倍精度、または文字列ポインタがあるかどうかを知る必要がある場合、
代わりに次の XNUMX つのマクロを使用できます。
SvIOKp(SV*)
SvNOKp(SV*)
SvPOKp(SV*)
これらは、実際に整数、倍精度、または文字列ポインターが保存されているかどうかを示します。
SV。 「p」はプライベートを表します。
プライベートフラグとパブリックフラグはさまざまな方法で異なる場合があります。 たとえば、
Perl 5.16 以前では、結合された SV は IV スロットに有効な基礎となる値を持つ可能性があります (つまり
SvIOKp は true)、ただしデータには FETCH ルーチンを介してアクセスする必要があります。
直接なので、SvIOK は false になります。 (Perl 5.18 以降では、タイド スカラーは同じフラグを使用します
もう XNUMX つは、数値変換が発生し、精度が低下した場合です。
失われた: プライベート フラグのみが「損失のある」値に設定されます。 したがって、NV がに変換されると、
損失のある IV、SvIOKp、SvNOKp、および SvNOK は設定されますが、SvIOK は設定されません。
ただし、一般的には、「Sv*V」マクロを使用するのが最善です。
ワーキング AV
AV を作成してロードするには XNUMX つの方法があります。 最初の方法では、空の AV を作成します。
AV* newAV();
XNUMX 番目の方法では、AV を作成し、最初に SV を設定します。
AV* av_make(SSize_t num, SV **ptr);
XNUMX 番目の引数は、「num」個の「SV*」を含む配列を指します。 AVが完成したら
SV が作成された後、必要に応じて SV を破棄できます。
AV が作成されると、それに対して次の操作が可能になります。
void av_push(AV*, SV*);
SV* av_pop(AV*);
SV* av_shift(AV*);
void av_unshift(AV*, SSize_t num);
「av_unshift」を除いて、これらはよく知られた操作です。 このルーチン
「undef」値を持つ「num」要素を配列の先頭に追加します。 次に使用する必要があります
「av_store」(後述) は、これらの新しい要素に値を割り当てます。
その他の機能は次のとおりです。
SSize_t av_top_index(AV*);
SV** av_fetch(AV*, SSize_t key, I32 lval);
SV** av_store(AV*, SSize_t キー, SV* val);
「av_top_index」関数は、配列内の最大のインデックス値を返します ($#array と同様)
Perl では)。 配列が空の場合は、-1 が返されます。 「av_fetch」関数は、
インデックス「key」に値が格納されますが、「lval」がゼロ以外の場合、「av_fetch」は undef 値を格納します
そのインデックスで。 「av_store」関数は、値「val」をインデックス「key」に格納し、
「val」の参照カウントをインクリメントしません。 したがって、呼び出し側は次のことを行う責任があります。
それは気にしてください。「av_store」が NULL を返した場合、呼び出し元はその値をデクリメントする必要があります。
メモリリークを避けるための参照カウント。 「av_fetch」と「av_store」は両方とも返されることに注意してください。
戻り値は「SV*」ではなく「SV**」です。
さらにいくつかの:
void av_clear(AV*);
void av_undef(AV*);
void av_extend(AV*, SSize_t キー);
「av_clear」関数は AV* 配列内のすべての要素を削除しますが、実際には削除しません。
配列自体を削除します。 「av_undef」関数は、ファイル内のすべての要素を削除します。
配列と配列自体。 「av_extend」関数は配列を拡張して、
少なくとも「key+1」要素が含まれています。 「key+1」が現在割り当てられている値より小さい場合
配列の長さの場合は何も行われません。
配列変数の名前がわかっている場合は、次のコマンドを使用して、その AV へのポインタを取得できます。
次のとおりです。
AV* get_av("パッケージ::変数名", 0);
変数が存在しない場合は NULL を返します。
使用方法の詳細については、「結合ハッシュと配列の魔法を理解する」を参照してください。
配列アクセス関数は結合配列上で機能します。
ワーキング HV
HV を作成するには、次のルーチンを使用します。
HV* newHV();
HV が作成されると、それに対して次の操作が可能になります。
SV** hv_store(HV*, const char* キー, U32 klen, SV* val, U32 ハッシュ);
SV** hv_fetch(HV*, const char* キー, U32 klen, I32 lval);
「klen」パラメータは渡されるキーの長さです(0を渡すことはできないことに注意してください)
Perl にキーの長さを測定するように指示するために「klen」の値として入力します)。 「ヴァル」
引数には、保存されているスカラーへの SV ポインタが含まれており、「ハッシュ」は事前に計算された値です。
ハッシュ値 (「hv_store」に計算してもらいたい場合はゼロ)。 「lval」パラメータ
このフェッチが実際にストア操作の一部であるかどうかを示します。その場合、新しい
未定義の値が指定されたキーで HV に追加され、「hv_fetch」が返されます。
あたかもその値がすでに存在していたかのように。
「hv_store」と「hv_fetch」は「SV*」だけではなく「SV**」を返すことに注意してください。 にアクセスするには、
スカラー値を使用する場合は、最初に戻り値を逆参照する必要があります。 ただし、次のことを確認してください。
逆参照する前に、戻り値が NULL でないことを確認してください。
これら XNUMX つの関数のうち、最初の関数はハッシュ テーブル エントリが存在するかどうかを確認し、XNUMX 番目の関数はハッシュ テーブル エントリが存在するかどうかを確認します。
それを削除します。
bool hv_exists(HV*, const char* キー, U32 klen);
SV* hv_delete(HV*, const char* キー, U32 klen, I32 フラグ);
「flags」に「G_DISCARD」フラグが含まれていない場合、「hv_delete」は
削除された値の永久コピー。
その他のさまざまな機能:
void hv_clear(HV*);
void hv_undef(HV*);
対応する AV と同様に、「hv_clear」はハッシュ テーブル内のすべてのエントリを削除しますが、
実際にハッシュテーブルを削除するわけではありません。 「hv_undef」はエントリとハッシュの両方を削除します
テーブル自体。
Perl は、HE の typedef を持つ構造体のリンクされたリストに実際のデータを保持します。 これら
実際のキーと値のポインター (および追加の管理オーバーヘッド) が含まれています。 キー
文字列ポインタです。 値は「SV*」です。 ただし、「HE*」を取得すると、
実際のキーと値を取得するには、以下に指定するルーチンを使用します。
I32 hv_iterinit(HV*);
/* ハッシュ テーブルを走査するための開始点を準備します */
HE* hv_iternext(HV*);
/* 次のエントリを取得し、エントリへのポインタを返します。
キーと値の両方を持つ構造体 */
char* hv_iterkey(HE* エントリ、I32* retlen);
/* HE 構造体からキーを取得し、戻り値も返します
キー文字列の長さ */
SV* hv_iterval(HV*, HE* エントリ);
/* HE の値への SV ポインタを返します。
構造 */
SV* hv_iternextsv(HV*, char** キー, I32* retlen);
/* この便利なルーチンは、hv_iternext と、
hv_iterkey および hv_iterval。 キーとリレン
引数はキーとそのキーの戻り値です。
長さ。 値は SV* 引数 */ で返されます。
ハッシュ変数の名前がわかっている場合は、次のコマンドを使用してその HV へのポインタを取得できます。
次のとおりです。
HV* get_hv("パッケージ::変数名", 0);
変数が存在しない場合は NULL を返します。
ハッシュ アルゴリズムは、「PERL_HASH」マクロで定義されます。
PERL_HASH(ハッシュ、キー、クレン)
このマクロの正確な実装は、perl のアーキテクチャとバージョンによって異なります。
戻り値は呼び出しごとに変化する可能性があるため、値は呼び出しの期間のみ有効です。
単一の Perl プロセス。
使用方法の詳細については、「結合ハッシュと配列の魔法を理解する」を参照してください。
ハッシュ アクセスは、結合されたハッシュで機能します。
ハッシュ API 拡張機能
バージョン 5.004 以降、次の機能もサポートされています。
HE* hv_fetch_ent (HV* tb、SV* キー、I32 lval、U32 ハッシュ);
HE* hv_store_ent (HV* tb、SV* キー、SV* val、U32 ハッシュ);
bool hv_exists_ent (HV* tb、SV* キー、U32 ハッシュ);
SV* hv_delete_ent (HV* tb、SV* キー、I32 フラグ、U32 ハッシュ);
SV* hv_iterkeysv (HE* エントリ);
これらの関数は「SV*」キーを使用するため、拡張コードの記述が簡素化されることに注意してください。
ハッシュ構造を扱います。 これらの関数では、「SV*」キーを「tie」に渡すこともできます。
(以前の一連のキーとは異なり、キーを文字列化する必要がなくても機能します)
関数)。
また、ハッシュ エントリ全体 (「HE*」) を返したり受け入れたりするため、使用がより効率的になります。
(特定の文字列のハッシュ番号を毎回再計算する必要がないため)。
詳細な説明については、perlapi を参照してください。
ハッシュ エントリの内容にアクセスするには、次のマクロを常に使用する必要があります。 注記
これらのマクロの引数は評価される可能性があるため、単純な変数である必要があります。
一回以上。 これらのマクロの詳細な説明については、perlapi を参照してください。
HePV(HE*ヘ、STRLENレン)
HeVAL(ヘ・ヘ)
HeHASH(ヘ*ヘ)
HeSVKEY(ヘ・ヘ)
HeSVKEY_force(HE*ヘ)
HeSVKEY_set(HE* he, SV* sv)
これら XNUMX つの下位レベルのマクロが定義されていますが、キーを処理する場合にのみ使用する必要があります。
「SV*」ではないもの:
HeKEY(ヘ・ヘ)
ヘクレン(ヘクレン)
「hv_store」と「hv_store_ent」は両方とも、
格納された「val」。これは呼び出し側の責任です。 これらの関数が NULL を返した場合
通常、呼び出し側は、「val」の参照カウントをデクリメントして、エラーを回避する必要があります。
メモリーリーク。
AV、 HV と 未定義 値
場合によっては、AV または HV に未定義の値を保存しなければならないことがあります。 これは珍しいことかもしれませんが、
場合によっては、難しい場合があります。 これは、必要な場合に &PL_sv_undef を使用することに慣れているためです。
未定義のSV。
たとえば、直感的には、この XS コードは次のようになります。
AV *av = newAV();
av_store( av, 0, &PL_sv_undef );
これは次の Perl コードと同等です。
私の@av;
$av[0] = undef;
残念ながら、これは真実ではありません。 Perl 5.18 以前では、AV は &PL_sv_undef を
配列要素がまだ初期化されていないことを示すマーカー。 したがって、「存在する
$av[0]" は、上記の Perl コードでは true ですが、XS によって生成された配列では false になります。
コード。 Perl 5.20 では、&PL_sv_undef を格納すると読み取り専用要素が作成されます。
スカラー &PL_sv_undef 自体はコピーではなく保存されます。
&PL_sv_undef を HV に保存するときにも同様の問題が発生する可能性があります。
hv_store( hv, "キー", 3, &PL_sv_undef, 0 );
これで確かに値は「undef」になりますが、「key」の値を変更しようとすると、
次のエラーが表示されます。
作成不可能なハッシュ値の変更が試行されました
Perl 5.8.0 では、&PL_sv_undef は、制限されたハッシュ内のプレースホルダーをマークするためにも使用されました。 これ
そのため、ハッシュを反復処理するとき、またはハッシュをチェックするときに、そのようなハッシュ エントリが表示されなくなりました。
「hv_exists」機能を備えたキー。
&PL_sv_yes または &PL_sv_no を AV または HV に保存するときにも、同様の問題が発生する可能性があります。
このような要素を変更しようとすると、次のエラーが発生します。
読み取り専用値の変更が試行されました
簡単に言うと、特殊変数 &PL_sv_undef、&PL_sv_yes、および
AV と HV では &PL_sv_no を使用しますが、何をしているのかを必ず理解する必要があります。
一般に、未定義の値を AV または HV に保存する場合は、次のコマンドを使用しないでください。
&PL_sv_undef ではなく、「newSV」関数を使用して新しい未定義の値を作成します。
例:
av_store( av, 42, 新しいSV(0) );
hv_store( hv, "foo", 3, 新しいSV(0)、0);
参考情報
参照は、他のデータ型 (他のデータ型を含む) を指す特殊なタイプのスカラーです。
参考文献)。
参照を作成するには、次のいずれかの関数を使用します。
SV* newRV_inc((SV*) のもの);
SV* newRV_noinc((SV*) のもの);
「thing」引数には、「SV*」、「AV*」、または「HV*」のいずれかを指定できます。 機能は同じです
ただし、「newRV_inc」は「モノ」の参照カウントをインクリメントしますが、「newRV_noinc」は「モノ」の参照カウントをインクリメントします。
ではない。 歴史的な理由から、「newRV」は「newRV_inc」の同義語です。
参照を取得したら、次のマクロを使用して参照を逆参照できます。
SvRV(SV*)
次に、適切なルーチンを呼び出し、返された「SV*」を「AV*」または「AV*」のいずれかにキャストします。
必要に応じて「HV*」。
SV が参照であるかどうかを判断するには、次のマクロを使用できます。
SvROK(SV*)
参照が参照している値のタイプを確認するには、次のマクロを使用してから、
戻り値を確認してください。
SvTYPE(SvRV(SV*))
返される最も有用な型は次のとおりです。
< SVt_PVAV スカラー
SVt_PVAV 配列
SVt_PVHV ハッシュ
SVt_PVCV コード
SVt_PVGV Glob (おそらくファイル ハンドル)
詳細については、perlapi の「svtype」を参照してください。
恵まれた 参考情報 と CLASS オブジェクト
参照は、オブジェクト指向プログラミングをサポートするためにも使用されます。 Perl の OO レキシコンでは、
object は、パッケージ (またはクラス) に祝福された単なる参照です。 一度
幸いなことに、プログラマは参照を使用して、
とに提供されます。
参照は、次の関数を使用してパッケージに含めることができます。
SV* sv_bless(SV* sv, HV* スタッシュ);
引数「sv」は参照値である必要があります。 「stash」引数はどのクラスを指定しますか
参照はに属します。 クラスの変換については、「スタッシュとグロブ」を参照してください。
名前を隠し場所に追加します。
/* まだ準備中です */
次の関数は、rv をまだ参照にアップグレードしていない場合は参照にアップグレードします。 新しい SV を作成します
rvを指す。 「classname」が null 以外の場合、SV は指定されたクラスに祝福されます。
SVが返されます。
SV* newSVrv(SV* rv, const char* クラス名);
次の XNUMX つの関数は、整数、符号なし整数、または double を SV にコピーします。
参照は「rv」です。 「classname」が null でない場合、SV は祝福されます。
SV* sv_setref_iv(SV* rv, const char* クラス名, IV iv);
SV* sv_setref_uv(SV* rv, const char* クラス名, UV uv);
SV* sv_setref_nv(SV* rv, const char* クラス名, NV iv);
次の関数はポインター値をコピーします ( 住所、 弦!) SV に
その参照はrvです。 「classname」が null でない場合、SV は祝福されます。
SV* sv_setref_pv(SV* rv, const char* クラス名, void* pv);
次の関数は、参照が「rv」である SV に文字列をコピーします。 長さを次のように設定します
0 を指定すると、Perl が文字列の長さを計算します。 「classname」が null でない場合、SV は祝福されます。
SV* sv_setref_pvn(SV* rv, const char* クラス名, char* pv,
STRLEN 長さ);
次の関数は、SV が指定されたクラスに祝福されているかどうかをテストします。 します
継承関係をチェックしません。
int sv_isa(SV* sv, const char* 名前);
次の関数は、SV が祝福されたオブジェクトへの参照であるかどうかをテストします。
int sv_isobject(SV* sv);
次の関数は、SV が指定されたクラスから派生したかどうかをテストします。 SV缶
祝福されたオブジェクトへの参照、またはクラス名を含む文字列のいずれかです。 これは
「UNIVERSAL::isa」機能を実装する関数。
bool sv_derived_from(SV* sv, const char* 名前);
特定のクラスから派生したオブジェクトがあるかどうかを確認するには、次のように記述する必要があります。
if (sv_isobject(sv) && sv_derived_from(sv, class)) { ... }
作成 New Variables
Perl からアクセスできる undef 値を持つ新しい Perl 変数を作成するには
スクリプトでは、変数のタイプに応じて次のルーチンを使用します。
SV* get_sv("パッケージ::変数名", GV_ADD);
AV* get_av("パッケージ::変数名", GV_ADD);
HV* get_hv("パッケージ::変数名", GV_ADD);
XNUMX 番目のパラメーターとして GV_ADD が使用されていることに注目してください。 これで、次を使用して新しい変数を設定できるようになります。
データ型に適したルーチン。
値を「GV_ADD」引数とビットごとの OR 演算できる追加のマクロがあります。
特定の追加機能を有効にします。 それらのビットは次のとおりです。
GV_ADDMULTI
変数を多重定義としてマークし、次のことを防ぎます。
名前XNUMX 回のみ使用: タイプミスの可能性があります
警告。
GV_ADDWARN
次の警告を発行します。
作成しなければならなかった思いがけず
関数が呼び出される前に変数が存在しなかった場合。
パッケージ名を指定しない場合、変数は現在のパッケージ内に作成されます。
参照 カウント と 死亡率
Perl は、参照カウント主導のガベージ コレクション メカニズムを使用します。 SV、AV、または HV (xV
以下では省略します) 参照カウント 1 からライフを開始します。
xV のカウントが 0 になると、xV は破棄され、そのメモリが利用可能になります。
再利用のために。
通常、変数が未定義であるか、最後の変数でない限り、これは Perl レベルでは起こりません。
参照を保持する変数が変更または上書きされます。 内部レベルでは、
ただし、参照カウントは次のマクロを使用して操作できます。
int SvREFCNT(SV* sv);
SV* SvREFCNT_inc(SV* sv);
void SvREFCNT_dec(SV* sv);
ただし、その参照カウントを操作する関数がもう XNUMX つあります。
口論。 「newRV_inc」関数は、指定されたオブジェクトへの参照を作成することを思い出してください。
口論。 副作用として、引数の参照カウントが増加します。 そうでない場合
代わりに「newRV_noinc」を使用してください。
たとえば、XSUB 関数から参照を返したいとします。 内部
XSUB ルーチンでは、最初に参照カウントが XNUMX である SV を作成します。 それからあなた
「newRV_inc」を呼び出し、作成したばかりの SV を渡します。 これにより、参照が新しい SV として返されます。
ただし、「newRV_inc」に渡した SV の参照カウントは XNUMX に増加しています。
ここで、XSUB ルーチンから参照を返し、SV のことは忘れます。 しかし、パール
そうではありません! 返された参照が破棄されるたびに、元の参照カウントは
SV が XNUMX に減少しても何も起こりません。 SV は何もすることなくうろうろします。
Perl 自体が終了するまでアクセスしてください。 これはメモリリークです。
したがって、正しい手順は、「newRV_inc」の代わりに「newRV_noinc」を使用することです。 そして、もし、そして
最後の参照が破棄されると、SV の参照カウントはゼロになり、
が破棄され、メモリ リークが停止されます。
xV の破棄に役立つ便利な関数がいくつかあります。
これらの関数には、「死亡率」の概念が導入されています。 致命的な xV には、
参照カウントはデクリメントされるようにマークされていますが、実際にはデクリメントされません。
通常、「しばらく後」という用語は、次のような単一の Perl ステートメントを意味します。
XSUB 関数の呼び出し。 定命の xV がいつその能力を発揮するかを決定する実際の要因
デクリメントされる参照カウントは、SAVETMPS と FREETMPS の XNUMX つのマクロに依存します。 perlcall を参照
これらのマクロの詳細については、perlxs を参照してください。
「モータリゼーション」は最も単純な、遅延された「SvREFCNT_dec」です。 ただし、もしあなたが
変数を XNUMX 回消滅させると、参照カウントは後で XNUMX 回デクリメントされます。
「Mortal」SV は主に Perl のスタックに配置される SV に使用されます。 たとえばSV
呼び出されたサブルーチンに番号を渡すためだけに作成されたものは、クリーンアップするために致命的になります
スタックからポップされると自動的に立ち上がります。 同様に、XSUB によって返される結果
(スタックにプッシュされる) は致命的になることがよくあります。
mortal 変数を作成するには、次の関数を使用します。
SV* sv_newmortal()
SV* sv_2mortal(SV*)
SV* sv_mortalcopy(SV*)
最初の呼び出しでは、致命的な SV (値なし) が作成され、XNUMX 番目の呼び出しでは、既存の SV が
定命の SV (したがって「SvREFCNT_dec」への呼び出しを延期)、XNUMX 番目は定命の SV を作成します。
既存の SV のコピー。 「sv_newmortal」は新しい SV に値を与えないため、
通常は、「sv_setpv」、「sv_setiv」などによって指定されます。
SV *tmp = sv_newmortal();
sv_setiv(tmp, an_integer);
これは複数の C ステートメントであるため、非常に一般的なので、代わりにこのイディオムを参照してください。
SV *tmp = sv_2mortal(newSViv(an_integer));
致命的な変数の作成には注意する必要があります。 あなたがそうするなら、奇妙なことが起こるかもしれません
複数のコンテキスト内で同じ値を mortal にするか、変数を mortal にする場合
複数回。 「モータリゼーション」を延期された「SvREFCNT_dec」と考えると、
そのような問題を最小限に抑えます。 たとえば、SV を渡す場合、 知っています 高い
スタック上での使用を存続させるのに十分な REFCNT があれば、死滅化を行う必要はありません。 もし、あんたが
よくわからない場合は、「SvREFCNT_inc」と「sv_2mortal」を実行するか、「sv_mortalcopy」を作成します。
より安全。
定命の日のルーチンは SV だけのものではありません。 AV と HV は、
アドレス (「SV*」にタイプキャスト) を「sv_2mortal」または「sv_mortalcopy」ルーチンに渡します。
隠し場所 と グロブ
A 隠れる パッケージ内で定義されているすべての変数を含むハッシュです。 各キー
スタッシュの はシンボル名です (
同じ名前)、ハッシュ テーブルの各値は GV(Glob Value)です。 この GV は順番に
その名前のさまざまなオブジェクトへの参照が含まれます (ただし、これに限定されません)。
以下
スカラー値
配列値
ハッシュ値
I/Oハンドル
フォーマット
サブルーチン
「PL_defstash」と呼ばれる単一のスタッシュがあり、「メイン」に存在するアイテムを保持します。
パッケージ。 他のパッケージ内の項目を取得するには、パッケージに文字列「::」を追加します。
名前。 「Foo」パッケージ内のアイテムは、PL_defstash のスタッシュ「Foo::」にあります。 アイテム
「Bar::Baz」パッケージ内のファイルは、「Bar::」のスタッシュ内の「Baz::」スタッシュにあります。
特定のパッケージのスタッシュ ポインターを取得するには、次の関数を使用します。
HV* gv_stashpv(const char* 名前、I32 フラグ)
HV* gv_stashsv(SV*、I32 フラグ)
最初の関数はリテラル文字列を受け取り、XNUMX 番目の関数は SV に保存されている文字列を使用します。
スタッシュは単なるハッシュ テーブルであるため、「HV*」が返されることに注意してください。 「フラグ」の旗
GV_ADD に設定されている場合は、新しいパッケージが作成されます。
「gv_stash*v」が指定する名前は、必要なシンボル テーブルが含まれるパッケージの名前です。
デフォルトのパッケージは「main」と呼ばれます。 複数のネストされたパッケージがある場合は、それらのパッケージを渡します
Perl 言語自体と同様に、名前を「::」で区切って「gv_stash*v」にします。
あるいは、祝福された参照である SV がある場合は、隠し場所を見つけることができます。
次を使用してポインタを作成します。
HV* SvSTASH(SvRV(SV*));
次に、以下を使用してパッケージ名自体を取得します。
char* HvNAME(HV* スタッシュ);
オブジェクトを祝福または再祝福する必要がある場合は、次の関数を使用できます。
SV* sv_bless(SV*、HV* スタッシュ)
ここで、最初の引数「SV*」は参照である必要があり、XNUMX 番目の引数は
隠し場所。 返された「SV*」は、他の SV と同じように使用できるようになりました。
参照と祝福の詳細については、perlref を参照してください。
二重型 SV
スカラー変数には通常、整数、double、ポインタ、または XNUMX つのタイプの値のみが含まれます。
参照。 Perl は、格納された型から実際のスカラー データを自動的に変換します。
要求されたタイプに変換します。
一部のスカラー変数には、複数のタイプのスカラー データが含まれています。 たとえば、
変数 $! 「errno」の数値、またはそれに相当する文字列が含まれます。
「strerror」または「sys_errlist[]」のいずれか。
複数のデータ値を強制的に SV に入れるには、次の XNUMX つのことを行う必要があります。「sv_set*v」を使用します。
ルーチンで追加のスカラー型を追加し、Perl がそれを信じるようにフラグを設定します。
複数の種類のデータが含まれています。 フラグを設定する XNUMX つのマクロは次のとおりです。
SvIOK_on
SvNOK_on
SvPOK_on
SvROK_on
使用する必要がある特定のマクロは、最初にどの「sv_set*v」ルーチンを呼び出したかによって異なります。
これは、すべての「sv_set*v」ルーチンが特定のタイプのビットのみをオンにするためです。
設定中のデータをすべてオフにし、残りをすべてオフにします。
たとえば、両方の数値を含む「dberror」という新しい Perl 変数を作成するには、
および説明的な文字列エラー値を指定するには、次のコードを使用できます。
extern int dberror;
extern char *dberror_list;
SV* sv = get_sv("dberror", GV_ADD);
sv_setiv(sv, (IV) dberror);
sv_setpv(sv, dberror_list[dberror]);
SvIOK_on(sv);
「sv_setiv」と「sv_setpv」の順序が逆だった場合、マクロ「SvPOK_on」
「SvIOK_on」の代わりに呼び出す必要があります。
読み取り専用 価値観
Perl 5.16 以前では、コピーオンライト (次のセクションを参照) はフラグ ビットを共有していました。
読み取り専用のスカラー。 したがって、「sv_setsv」などが発生するかどうかをテストする唯一の方法は、
これらのバージョンでの「読み取り専用値の変更」エラーは次のとおりです。
SvREADONLY(sv) && !SvIsCOW(sv)
Perl 5.18 以降では、SvREADONLY は読み取り専用変数にのみ適用されます。
5.20 では、コピーオンライト スカラーも読み取り専用になる可能性があるため、上記のチェックは正しくありません。 あなた
ただ欲しい:
SvREADONLY(sv)
このチェックを頻繁に行う必要がある場合は、次のように独自のマクロを定義します。
#if PERL_VERSION >= 18
# SvTRULYREADONLY(sv) SvREADONLY(sv) を定義します
#その他
# SvTRULYREADONLY(sv) を定義します (SvREADONLY(sv) && !SvIsCOW(sv))
#endif
コピー on 書きます
Perl は、スカラー用のコピーオンライト (COW) メカニズムを実装しています。
要求されてもすぐに作成されるのではなく、どちらかが必要とするまで延期されます。
他のスカラーの変更。 これはほとんど透明ですが、変更しないように注意する必要があります。
複数のSVによって共有される文字列バッファ。
「SvIsCOW(sv)」を使用して、SV がコピーオンライトを使用しているかどうかをテストできます。
次を呼び出すことで、SV に文字列バッファの独自のコピーを強制的に作成させることができます。
「sv_force_normal(sv)」または SvPV_force_nolen(sv)。
SV に文字列バッファを削除させたい場合は、「sv_force_normal_flags(sv,
SV_COW_DROP_PV)」または単に「sv_setsv(sv, NULL)」。
これらの関数はすべて、読み取り専用スカラーでクロークします (詳細については、前のセクションを参照してください)
それらについて)。
システム上でコードが正しく動作し、COW バッファを変更していないことをテストするには
そのサポート mmap(2) (つまり Unix) Perl を設定できるのは
"-Accflags=-DPERL_DEBUG_READONLY_COW" とすると、バッファー違反がクラッシュに変わります。
驚くほど遅いことがわかるので、perl 自体のテストをスキップしたくなるかもしれません。
Variables
[このセクションはまだ作成中です。 ここではすべてを無視してください。 請求書を投稿しないでください。
許可されていないものはすべて禁止されています。】
どの SV も魔法である可能性があります。つまり、通常の SV にはない特別な機能を備えています。
これらの機能は、「構造マジック」のリンクされたリスト内の SV 構造に保存されます。
typedef は「MAGIC」に設定されています。
構造体マジック {
MAGIC* mg_moremagic;
MGVTBL* mg_virtual;
U16 mg_プライベート;
char mg_type;
U8 mg_flags;
I32 mg_len;
SV* mg_obj;
char* mg_ptr;
};
これはパッチレベル 0 の時点でのものであり、いつでも変更される可能性があることに注意してください。
割り当て
Perl は、sv_magic 関数を使用して SV にマジックを追加します。
void sv_magic(SV* sv, SV* obj, int how, const char* 名前, I32 namlen);
「sv」引数は、新しい魔法の機能を取得する SV へのポインタです。
「sv」がまだマジカルでない場合、Perl は「SvUPGRADE」マクロを使用して「sv」を type に変換します。
「SVt_PVMG」。 Perl は、リンクされたリストの先頭に新しいマジックを追加して続行します。
魔法の機能の。 同じ種類の魔法の以前のエントリは削除されます。 ご了承ください
これはオーバーライドでき、同じ種類の魔法の複数のインスタンスを関連付けることができます。
SV付き。
「name」引数と「namlen」引数は、文字列をマジックに関連付けるために使用されます。通常、
変数の名前。 「namlen」は「mg_len」フィールドに格納され、「name」が非
null の場合、「name」の「savepvn」コピー、または「name」自体が「mg_ptr」に保存されます。
フィールドは、「namlen」がゼロより大きいかゼロに等しいかによって異なります。
特殊なケースとして、「(name && namlen == HEf_SVKEY)」の場合、「name」には
「SV*」は、REFCNT をインクリメントした状態でそのまま保存されます。
sv_magic 関数は、事前定義された「Magic Virtual」が存在する場合、その「方法」を使用して決定します。
Table」を「mg_virtual」フィールドに割り当てる必要があります。「Magic Virtual Tables」を参照してください。
以下のセクション。 「how」引数も「mg_type」フィールドに格納されます。 の値
にあるマクロのセット「PERL_MAGIC_foo」から「どのように」選択する必要がありますか perl.h。 ご了承ください
これらのマクロが追加される前は、Perl 内部では文字リテラルを直接使用していました。
時々、「U」マジックについて言及している古いコードやドキュメントに遭遇することがあります。
たとえば「PERL_MAGIC_uvar」よりも。
「obj」引数は、「MAGIC」構造体の「mg_obj」フィールドに格納されます。 そうでない場合
"sv" 引数と同様に、"obj" オブジェクトの参照カウントがインクリメントされます。 もし
同じであるか、「how」引数が「PERL_MAGIC_arylen」であるか、NULL である場合
ポインタの場合、「obj」は参照カウントがインクリメントされずに単に格納されるだけです。
SV にマジックを追加するより柔軟な方法については、perlapi の「sv_magicext」も参照してください。
「HV」に魔法を加える機能もあります。
void hv_magic(HV *hv, GV *gv, int how);
これは単に「sv_magic」を呼び出し、「gv」引数を「SV」に強制します。
SV からマジックを削除するには、関数 sv_unmagic を呼び出します。
int sv_unmagic(SV *sv, int 型);
「type」引数は、「SV」が最初に作成されたときの「how」値と同じである必要があります。
魔法の。
ただし、「sv_unmagic」は特定の「タイプ」の魔法をすべて「SV」から削除することに注意してください。 もし
マジック仮想テーブルに基づいて「タイプ」の特定のマジックのみを削除したい場合は、次を使用します。
代わりに「sv_unmagicext」:
int sv_unmagicext(SV *sv, int 型, MGVTBL *vtbl);
バーチャル テーブル類
「MAGIC」構造体の「mg_virtual」フィールドは、「MGVTBL」へのポインタです。
関数ポインタの構造と、さまざまな関数を処理するための「Magic Virtual Table」の略です。
その変数に適用される可能性のある操作。
「MGVTBL」には、次のルーチン タイプへの XNUMX つ (場合によっては XNUMX つ) のポインターがあります。
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 *name, I32 namlen);
int (*svt_dup)(MAGIC *mg, CLONE_PARAMS *param);
int (*svt_local)(SV *nsv, MAGIC *mg);
この MGVTBL 構造体はコンパイル時に設定されます。 perl.h 現在32種類あります。
これらのさまざまな構造には、追加の実行を実行するさまざまなルーチンへのポインタが含まれています。
どの関数が呼び出されているかに応じてアクションが異なります。
関数ポインタ 実行されたアクション
---------------- ------------
svt_get SV の値が取得される前に何かを行う
取得しました。
svt_set SV に値が割り当てられた後に何かを実行します。
svt_len SV の長さに関するレポート。
svt_clear SV が表すものをクリアします。
svt_free SV に関連付けられた余分なストレージを解放します。
svt_copy 関連付けられた変数マジックを関連付けられた要素にコピーします
svt_dup はスレッドのクローン作成中にマジック構造を複製します。
svt_local 「ローカル」中にマジックをローカル値にコピーします
たとえば、「vtbl_sv」という MGVTBL 構造体 (これは、
"PERL_MAGIC_sv") には次のものが含まれます。
{ マジックゲット、マジックセット、マジックレン、0、0 }
したがって、SV がマジカルでタイプ「PERL_MAGIC_sv」であると判断された場合、
操作が実行されると、ルーチン「magic_get」が呼び出されます。 さまざまなルーチンすべて
さまざまな魔法のタイプは「magic_」で始まります。 注: マジック ルーチンはそうではありません。
Perl API の一部とみなされ、Perl ライブラリによってエクスポートできない場合があります。
最後の XNUMX つのスロットは最近追加されたもので、ソース コードの互換性のために
MGf_COPY、MGf_DUP、または MGf_LOCAL の XNUMX つのフラグのいずれかが設定されているかどうかのみチェックされます。
mg_flags。 これは、ほとんどのコードが引き続き vtable を 5 要素の値として宣言できることを意味します。
これら XNUMX つは現在、スレッド コードによってのみ使用されており、非常に重要です。
変更します。
現在の Magic Virtual Table の種類は次のとおりです。
mg_type
(旧形式の文字とマクロ) MGVTBL マジックの種類
------------------------ ------ -------------
\0 PERL_MAGIC_sv vtbl_sv 特殊なスカラー変数
# PERL_MAGIC_arylen vtbl_arylen 配列の長さ ($#ary)
% PERL_MAGIC_rhash (なし) 制限付きの追加データ
ハッシュ
* PERL_MAGIC_debugvar vtbl_debugvar $DB::single、信号、トレース
VARS
。 PERL_MAGIC_pos vtbl_pos pos() lvalue
: PERL_MAGIC_symtab (なし) シンボルの追加データ
テーブル
< PERL_MAGIC_backref vtbl_backref 弱い参照データの場合
@ PERL_MAGIC_arylen_p (なし) arylen を XPVAV から移動するには
B PERL_MAGIC_bm vtbl_regexp ボイヤー・ムーア
(高速文字列検索)
c PERL_MAGIC_overload_table vtbl_ovrld オーバーロード テーブルを保持します。
(AMT) 隠し場所にあります
D PERL_MAGIC_regdata vtbl_regdata 正規表現一致位置データ
(@+ および @- 変数)
d PERL_MAGIC_regdatum vtbl_regdatum 正規表現一致位置データ
素子
E PERL_MAGIC_env vtbl_env %ENV ハッシュ
e PERL_MAGIC_envelem vtbl_envelem %ENV ハッシュ要素
f PERL_MAGIC_fm vtbl_regexp フォームライン
(「コンパイル済み」形式)
g PERL_MAGIC_regex_global vtbl_mglob m//g ターゲット
H PERL_MAGIC_hints vtbl_hints %^H ハッシュ
h PERL_MAGIC_hintselem vtbl_hintselem %^H ハッシュ要素
I PERL_MAGIC_isa vtbl_isa @ISA 配列
i PERL_MAGIC_isaelem vtbl_isaelem @ISA 配列要素
k PERL_MAGIC_nkeys vtbl_nkeys スカラー(keys()) 左辺値
L PERL_MAGIC_dbfile (なし) デバッガー %_
l PERL_MAGIC_dbline vtbl_dbline デバッガー %_
素子
N PERL_MAGIC_shared (なし) スレッド間で共有
n PERL_MAGIC_shared_scalar (なし) スレッド間で共有
o PERL_MAGIC_collxfrm vtbl_collxfrm ロケール変換
P PERL_MAGIC_tied vtbl_pack 結合された配列またはハッシュ
p PERL_MAGIC_tiedelem vtbl_packelem 結合された配列またはハッシュ要素
q PERL_MAGIC_tiedscalar vtbl_packelem 結合されたスカラーまたはハンドル
r PERL_MAGIC_qr vtbl_regexp プリコンパイルされた qr// 正規表現
S PERL_MAGIC_sig (なし) %SIG ハッシュ
PERL_MAGIC_sigelem vtbl_sigelem %SIG ハッシュ要素
t PERL_MAGIC_taint vtbl_taint 汚染度
U PERL_MAGIC_uvar vtbl_uvar で使用可能
エクステンション
u PERL_MAGIC_uvar_elem (なし) による使用のために予約されています。
エクステンション
V PERL_MAGIC_vstring (なし) SV は vstring リテラルでした
v PERL_MAGIC_vec vtbl_vec vec() 左辺値
w PERL_MAGIC_utf8 vtbl_utf8 キャッシュされた UTF-8 情報
x PERL_MAGIC_substr vtbl_substr substr() lvalue
y PERL_MAGIC_defelem vtbl_defelem シャドウ「foreach」イテレータ
変数/スマートパラメータ
生き生きとした
\ PERL_MAGIC_lvref vtbl_lvref 左辺値リファレンス
コンストラクタ
] PERL_MAGIC_checkcall vtbl_checkcall 呼び出しのインライン化/変更
この履歴書に
~ PERL_MAGIC_ext (なし) で使用可能
エクステンション
テーブル内に大文字と小文字の両方が存在する場合、大文字が
通常、ある種の複合型 (リストまたはハッシュ) を表すために使用されます。
小文字は、その複合型の要素を表すために使用されます。 内部の一部
コードはこの大文字と小文字の関係を利用します。 ただし、「v」と「V」(vec と v-string)は
関係ありません。
「PERL_MAGIC_ext」および「PERL_MAGIC_uvar」マジック タイプは、特に次のユーザーが使用するために定義されています。
拡張機能であり、perl 自体では使用されません。 拡張機能は「PERL_MAGIC_ext」マジックを使用できます
個人情報を変数 (通常はオブジェクト) に「添付」します。 これは特に
通常の Perl コードではこの個人情報を破損する方法がないので便利です
(ハッシュ オブジェクトの追加要素を使用するのとは異なります)。
同様に、「PERL_MAGIC_uvar」マジックは次のように使用できます。 タイ() C 関数を呼び出すには
スカラーの値が使用または変更された時間。 「MAGIC」の「mg_ptr」フィールドは、
「ufuncs」構造体:
構造体 ufuncs {
I32 (*uf_val)(pTHX_IV、SV*);
I32 (*uf_set)(pTHX_IV、SV*);
IV uf_index;
};
SV の読み取りまたは書き込み時には、「uf_val」または「uf_set」関数が呼び出されます。
最初の引数として「uf_index」、XNUMX 番目の引数として SV へのポインタを使用します。 簡単な例
「PERL_MAGIC_uvar」マジックの追加方法を以下に示します。 ufuncs 構造体は次のとおりであることに注意してください。
sv_magic によってコピーされるため、安全にスタックに割り当てることができます。
ボイド
ウマジック(SV)
SV *sv;
事前設定:
構造体 ufuncs uf;
CODE:
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));
「PERL_MAGIC_uvar」を配列に付加することは許容されますが、効果はありません。
ハッシュの場合は、ハッシュ キー (値ではなく) を制御する特殊なフックがあります。
このフックは、「ufuncs」の「set」関数の場合、「PERL_MAGIC_uvar」「get」マジックを呼び出します。
構造体が NULL です。 フックは、キーを使用してハッシュにアクセスするたびにアクティブ化されます。
関数「hv_store_ent」、「hv_fetch_ent」、「SV」として指定されます。
「hv_delete_ent」および「hv_exists_ent」。 関数を使用して文字列としてキーにアクセスする
「..._ent」接尾辞を付けないとフックが回避されます。 Hash::Util::FieldHash の「GUTS」を参照してください。
詳細な説明については。
複数の拡張機能が「PERL_MAGIC_ext」または「PERL_MAGIC_uvar」を使用している可能性があることに注意してください。
魔法のように、拡張機能では競合を避けるために細心の注意を払うことが重要です。 通常
拡張機能と同じクラスに祝福されたオブジェクトに対してのみマジックを使用します。
十分な。 「PERL_MAGIC_ext」マジックの場合、通常は「MGVTBL」を定義することをお勧めします。
たとえすべてのフィールドが 0 であっても、個々の「MAGIC」ポインタは次のように識別できます。
魔法の仮想テーブルを使用した特定の種類の魔法。 「mg_findext」は、
その方法:
STATIC MGVTBL my_vtbl = { 0, 0, 0, 0, 0, 0, 0, 0 };
マジック *mg;
if ((mg = mg_findext(sv, PERL_MAGIC_ext, &my_vtbl))) {
/* これは実際には私たちのものであり、別のモジュールの PERL_MAGIC_ext ではありません */
my_priv_data_t *priv = (my_priv_data_t *)mg->mg_ptr;
...
}
また、前に説明した「sv_set*()」関数と「sv_cat*()」関数は、 呼び出します
ターゲットに魔法を「設定」します。 これは、ユーザーが呼び出して実行する必要があります。
これらの関数を呼び出した後、または「sv_set*_mg()」のいずれかを使用して「SvSETMAGIC()」マクロを実行します。
または「sv_cat*_mg()」関数。 同様に、汎用 C コードは「SvGETMAGIC()」マクロを呼び出す必要があります。
関数で外部ソースから取得した SV を使用する場合に、「get」マジックを呼び出すため
魔法を扱わないもの。 これらの関数の説明については、perlapi を参照してください。 例えば、
通常、「sv_cat*()」関数の呼び出しの後には「SvSETMAGIC()」を続ける必要がありますが、
これらの実装は「get」マジックを処理するため、事前に「SvGETMAGIC()」を行う必要はありません。
検索
MAGIC *mg_find(SV *sv, int 型); /* そのマジック ポインタを見つけます
* タイプ */
このルーチンは、SV に格納されている「MAGIC」構造体へのポインタを返します。 SV がそうする場合
そのような魔法の機能がない場合は、「NULL」が返されます。 SV に複数のインスタンスがある場合、
その魔法の機能を使用すると、最初の機能が返されます。 「mg_findext」を使用して、
マジック タイプとマジック仮想テーブルの両方に基づく SV の「MAGIC」構造:
MAGIC *mg_findext(SV *sv, int 型, MGVTBL *vtbl);
また、「mg_find」または「mg_findext」に渡された SV が SVt_PVMG タイプではない場合、Perl がコアになる可能性があります。
投げ捨てる。
int mg_copy(SV* sv, SV* nsv, const char* key, STRLEN klen);
このルーチンは、「sv」がどのような種類の魔法を持っているかを確認します。 mg_type フィールドが
大文字の場合、mg_obj は「nsv」にコピーされますが、mg_type フィールドは次のように変更されます。
小文字にしてください。
理解する of タイド ハッシュ と 配列
Tied ハッシュと配列は、「PERL_MAGIC_tied」マジック タイプの魔法の獣です。
警告: 5.004 リリースでは、配列およびハッシュ アクセス関数を適切に使用する必要があります。
いくつかの注意点を理解する必要があります。 これらの注意事項の一部は実際にはバグと考えられています
API では、今後のリリースで修正される予定であり、以下では [MAYCHANGE] で囲まれています。 もし
このセクションでそのような情報を実際に適用していることに気付いた場合、次の点に注意してください。
将来、警告なしに動作が変更される可能性があります。
Perl のtie関数は、変数をさまざまな関数を実装するオブジェクトに関連付けます。
GET、SETなどのメソッド。 XSUB から Perl のtie 関数と同等の機能を実行するには、次のようにします。
この動作を真似する必要があります。 以下のコードは、必要な手順を実行します。まず、
新しいハッシュを作成し、次にクラスに祝福する XNUMX 番目のハッシュを作成します。
これにより、tie メソッドが実装されます。 最後に、XNUMX つのハッシュを結合して、次の値を返します。
新しい結合ハッシュへの参照。 以下のコードは TIEHASH を呼び出さないことに注意してください。
MyTie クラスのメソッド - 詳細については、「C プログラム内からの Perl ルーチンの呼び出し」を参照してください。
これを行う方法について。
SV*
マイティ()
事前設定:
HV *ハッシュ;
HV *スタッシュ;
SV *ネクタイ;
CODE:
ハッシュ = newHV();
tie = newRV_noinc((SV*)newHV());
stash = gv_stashpv("MyTie", GV_ADD);
sv_bless(ネクタイ、隠し場所);
hv_magic(ハッシュ, (GV*)tie, PERL_MAGIC_tied);
RETVAL = newRV_noinc(ハッシュ);
OUTPUT:
戻り値
「av_store」関数は、配列引数を結合して指定すると、単にそのマジックをコピーするだけです。
「mg_copy」を使用して、「保存」する値に配列を追加します。 NULL を返すこともあります。
実際には値を配列に格納する必要はなかったということです。 [変更の可能性があります] 通話後
結合された配列上の「av_store」にアクセスするには、呼び出し元は通常、「mg_set(val)」を呼び出す必要があります。
実際に、TIEARRAY オブジェクトに対して Perl レベルの「STORE」メソッドを呼び出します。 「av_store」が実行した場合
NULL を返す場合、通常は「SvREFCNT_dec(val)」の呼び出しも必要になります。
メモリーリーク。 [/MAYCHANGE]
前の段落は、「hv_store」と「hv_store」を使用した結合ハッシュ アクセスにそのまま適用できます。
「hv_store_ent」も機能します。
「av_fetch」とそれに対応するハッシュ関数「hv_fetch」と「hv_fetch_ent」は実際には
「mg_copy」を使用して魔法が初期化された未定義の致命的な値を返します。 注記
返された値はすでに致命的であるため、割り当てを解除する必要はありません。
[MAYCHANGE] ただし、次のことを行うには、戻り値に対して「mg_get()」を呼び出す必要があります。
実際には、基礎となる TIE オブジェクトに対して Perl レベルの「FETCH」メソッドを呼び出します。 同様に、
適切な値を割り当てた後、戻り値で「mg_set()」を呼び出すこともできます。
これには「sv_setsv」を使用します。これにより、TIE オブジェクトの「STORE」メソッドが呼び出されます。
[/MAYCHANGE]
[MAYCHANGE] 言い換えると、配列またはハッシュのフェッチ/ストア関数は実際にはフェッチしません。
結合された配列とハッシュの場合は実際の値を保存します。 彼らは単に「mg_copy」を呼び出すだけです
「保存」または「フェッチ」することを意図した値に魔法を付加します。 その後の電話
「mg_get」と「mg_set」は実際に、基盤となる TIE メソッドを呼び出す仕事を行います。
オブジェクト。 したがって、マジックメカニズムは現在、配列への一種の遅延アクセスを実装しています。
そしてハッシュ。
現在 (Perl バージョン 5.004 時点)、ハッシュおよび配列アクセス関数を使用するには、
ユーザーは、「通常の」ハッシュと配列を操作しているのか、それとも
彼らの結びつきのバリエーション。 API は、両方へのより透過的なアクセスを提供するために変更される可能性があります。
将来のバージョンでは、結合されたデータ型と通常のデータ型が追加されます。 [/MAYCHANGE]
TIEARRAY インターフェイスと TIEHASH インターフェイスは単なる糖分であることを理解しておくとよいでしょう。
統一ハッシュおよび配列構文を使用しながら、いくつかの Perl メソッド呼び出しを呼び出します。 の用法
このシュガーは、ある程度のオーバーヘッドを課します (通常、XNUMX つあたり約 XNUMX ~ XNUMX 個の追加のオペコード)
FETCH/STORE 操作に必要なすべての致命的な変数の作成に加えて、
メソッドを呼び出します)。 TIE メソッドが次のような場合、このオーバーヘッドは比較的小さくなります。
それ自体はかなりの量ですが、ステートメントが数行だけの長さであれば、オーバーヘッドは発生しません。
重要ではないこと。
ローカライズ 変更
Perl は非常に便利な構造を持っています
{
ローカル $var = 2;
...
}
この施工は、 約 に相当
{
私の $oldvar = $var;
$var = 2;
...
$var = $oldvar;
}
最大の違いは、最初の構築では初期値に戻ることです。
$var は、制御がどのようにブロックを終了するかに関係なく: "goto"、"return"、"die"/"eval" などです。
効率も少し向上します。
Perl API を介して C から同様のタスクを実現する方法があります。 擬似ブロック,
一部の変更は、明示的に、または終了時に自動的に元に戻されるように調整します。
ローカル出口以外から(経由) 死にます())。 ザ· コロナ新型ウィルス(COVID-XNUMX)やメンタルヘルスの崩壊を避ける為の-like 構造は、次のペアによって作成されます。
"ENTER"/"LEAVE" マクロ (perlcall の "スカラーを返す" を参照)。 このような構造は次のようになります。
重要なローカライズされたタスク、または既存のタスク (境界など) のために特別に作成されたもの
囲む Perl サブルーチン/ブロック、または TMP を解放するための既存のペア) を使用できます。
(XNUMX 番目のケースでは、追加のローカリゼーションのオーバーヘッドはほとんど無視できるほどである必要があります。)
XSUB は自動的に「ENTER」/「LEAVE」のペアで囲まれることに注意してください。
そんな中 擬似ブロック 以下のサービスが利用可能です。
「SAVEINT(int i)」
「SAVEIV(IV i)」
「SAVEI32(アイ32アイ)」
「SAVELONG(ロングアイ)」
これらのマクロは、整数変数「i」の値を最後に復元するように処理します。
囲う 擬似ブロック.
SAVESPTR
SAVEPPTR(p)
これらのマクロは、ポインタ「s」と「p」の値を復元するように処理します。 「s」は必ず
"SV*" への変換とその逆の変換に耐える型のポインタ、"p" は次のことができるはずです。
「char*」への変換とその逆の変換は生き残ります。
「SAVEFREESV(SV *sv)」
「sv」の refcount は、終了時にデクリメントされます。 擬似ブロック。 これも似ています
遅延された「SvREFCNT_dec」を実行するためのメカニズムでもあるという点で、「sv_2mortal」と同様です。
ただし、「sv_2mortal」は「sv」の存続期間を、
次のステートメント「SAVEFREESV」は、それを囲んでいるスコープの終わりまで拡張します。 これら
人生は大きく異なる可能性があります。
「SAVEMORTALIZESSV」も比較してみます。
「SAVEMORTALIZESSV(SV *sv)」
「SAVEFREESV」と同様ですが、「sv」は現在のスコープの最後で無効になります。
参照カウントをデクリメントします。 これには通常、「sv」を存続させる効果があります。
現在ライブ スコープを呼び出したステートメントの実行が完了するまで。
「SAVEFREEOP(OP *op)」
「OP*」は op_free()の最後に編集 擬似ブロック.
SAVEFREEPV(p)
「p」が指すメモリのチャンクは次のとおりです。 セーフフリー()の最後に編集 擬似-
コロナ新型ウィルス(COVID-XNUMX)やメンタルヘルスの崩壊を避ける為の.
「SAVECLEARSV(SV *sv)」
現在のスクラッチパッドの末尾の「sv」に対応するスロットをクリアします。
擬似ブロック.
"SAVEDELETE(HV *hv, char *key, I32 長さ)"
「hv」のキー「key」は最後に削除されます。 擬似ブロック。 が指す文字列
「鍵」は セーフフリー()編持っている場合 キー 短期間のストレージでは、対応する
string は次のように再割り当てできます。
SAVEDELETE(PL_defstash, savepv(tmpbuf), strlen(tmpbuf));
"SAVEDESTRUCTOR(DESTRUCTORFUNC_NOCONTEXT_t f, void *p)"
の終わりに 擬似ブロック 関数「f」は唯一の引数「p」を指定して呼び出されます。
"SAVEDESTRUCTOR_X(DESTRUCTORFUNC_t f, void *p)"
の終わりに 擬似ブロック 関数「f」は暗黙的なコンテキストで呼び出されます。
引数 (存在する場合)、および「p」。
「SAVESTACK_POS()」
Perl 内部スタック上の現在のオフセット (「SP」を参照) は、終了時に復元されます。
擬似ブロック.
次の API リストには関数が含まれているため、関数へのポインタを提供する必要があります。
明示的に変更可能なデータ (C ポインターまたは Perlish "GV *" のいずれか)。 上記の場所
マクロは「int」を受け取り、同様の関数は「int *」を受け取ります。
「SV* save_scalar(GV *gv)」
Perl コード「local $gv」に相当します。
「AV* save_ary(GV *gv)」
「HV* save_hash(GV *gv)」
「save_scalar」と似ていますが、@gv と %gv をローカライズします。
"void save_item(SV *item)"
現在の「ENTER」/「LEAVE」の終了時に、「SV」の現在の値を複製します。
擬似ブロック 保存された値を使用して「SV」の値を復元します。 扱いません
魔法。 魔法が影響を受ける場合は「save_scalar」を使用してください。
"void save_list(SV **sarg, I32 maxsarg)"
「SV*」の配列「sarg」を介して複数の引数を受け取る「save_item」のバリアント
長さは「maxsarg」です。
"SV* save_svref(SV **sptr)"
「save_scalar」と似ていますが、「SV *」を復元します。
「void save_aptr(AV **aptr)」
"void save_hptr(HV **hptr)"
「save_svref」と似ていますが、「AV *」と「HV *」をローカライズします。
「Alias」モジュールは、 電話をかけてきた人の スコープ.
含まれるスコープ内で物事をローカライズする方法に興味がある人は、
そこも見てください。
サブルーチン
XSUB と 引数 スタック
XSUB メカニズムは、Perl プログラムが C サブルーチンにアクセスする簡単な方法です。 XSUB
ルーチンには、Perl プログラムからの引数を含むスタックと、
Perl データ構造から C 相当のデータ構造にマップします。
スタック引数には、「n」番目のスタックを返す ST(n) マクロを通じてアクセスできます。
口論。 引数 0 は、Perl サブルーチン呼び出しで渡される最初の引数です。 これら
引数は「SV*」であり、「SV*」が使用されている場所ならどこでも使用できます。
ほとんどの場合、C ルーチンからの出力は RETVAL と
OUTPUT ディレクティブ。 ただし、引数スタックがまだ存在していない場合もあります。
すべての戻り値を処理するのに十分な長さ。 例としては、POSIX があります。 tzname() 電話、どれ
引数は取りませんが、ローカル タイム ゾーンの標準時間と夏時間の XNUMX つを返します。
略語。
この状況に対処するには、PPCODE ディレクティブが使用され、スタックは
大きい:
EXTEND(SP, 数値);
ここで、「SP」はスタック ポインタのローカル コピーを表すマクロ、「num」は
スタックを拡張する必要がある要素の数。
スタックに空きができたので、「PUSHs」マクロを使用して値をスタックにプッシュできます。 の
多くの場合、プッシュされた値は「死亡」である必要があります (「参照カウントと死亡率」を参照)。
PUSHs(sv_2mortal(newSViv(an_integer)))
PUSHs(sv_2mortal(newSVuv(an_unsigned_integer)))
PUSHs(sv_2mortal(newSVnv(a_double)))
PUSHs(sv_2mortal(newSVpv("何らかの文字列",0)))
/* 最後の例は、より適切に記述することができますが、
* 効率的: */
PUSHs(newSVpvs_flags("何らかの文字列", SVs_TEMP))
そして、Perl プログラムが「tzname」を呼び出すと、次のように XNUMX つの値が割り当てられます。
($standard_abbrev, $Summer_abbrev) = POSIX::tzname;
値をスタックにプッシュする代替 (そしておそらくより簡単な) 方法は、
大きい:
XPUSH(SV*)
このマクロは、必要に応じてスタックを自動的に調整します。したがって、次のことを行う必要はありません。
「EXTEND」を呼び出してスタックを拡張します。
このドキュメントの以前のバージョンでの提案にもかかわらず、マクロ「(X)PUSH[iunp]」
複数の結果を返す XSUB に適しています。 そのためには、
上記の「(X)PUSHs」マクロ、または代わりに新しい「m(X)PUSH[iunp]」マクロを使用してください。 見る
「C 値を Perl スタックに置く」。
詳細については、perlxs および perlxstut を参照してください。
自動読み込み XSUB
AUTOLOAD ルーチンが XSUB の場合、Perl サブルーチンと同様に、Perl は完全修飾された
XSUB のパッケージの $AUTOLOAD 変数内の自動ロードされたサブルーチンの名前。
ただし、XSUB 自体の特定のフィールドにも同じ情報が配置されます。
HV *stash = CvSTASH(cv);
const char *サブネーム = SvPVX(cv);
STRLEN 名前の長さ = SvCUR(cv); /* バイト単位 */
U32 is_utf8 = SvUTF8(cv);
「SvPVX(cv)」にはサブ名自体のみが含まれており、パッケージは含まれません。 オートロードの場合
UNIVERSAL またはそのスーパークラスのいずれかのルーチンで、「CvSTASH(cv)」が実行中に NULL を返します。
存在しないパッケージに対するメソッド呼び出し。
注意: XS AUTOLOAD サブをサポートしていない 5.6.1 では、$AUTOLOAD の設定が機能しなくなりました
全然。 Perl 5.8.0 では、XSUB 自体にフィールドの使用が導入されました。 Perl 5.16.0 が復元されました
$AUTOLOAD の設定。 5.8 ~ 5.14 をサポートする必要がある場合は、XSUB のフィールドを使用します。
呼び出し パール ルーチン from 以内 C プログラム
C 言語内から Perl サブルーチンを呼び出すために使用できるルーチンが XNUMX つあります。
プログラム。 これら XNUMX つは次のとおりです。
I32 call_sv(SV*, I32);
I32 call_pv(const char*, I32);
I32 call_method(const char*, I32);
I32 call_argv(const char*, I32, char**);
最もよく使用されるルーチンは「call_sv」です。 「SV*」引数には、次のいずれかの名前が含まれます。
呼び出される Perl サブルーチン、またはサブルーチンへの参照。 XNUMX 番目の引数
サブルーチンが呼び出されるコンテキストを制御するフラグで構成されます。
サブルーチンに引数が渡されていないこと、エラーをトラップする方法、およびその方法
戻り値を扱います。
XNUMX つのルーチンはすべて、サブルーチンが Perl で返した引数の数を返します。
スタック。
これらのルーチンは、Perl v5.6.0 より前では「perl_call_sv」などと呼ばれていましたが、それらの名前は
現在は非推奨となっています。 同じ名前のマクロは互換性のために提供されています。
これらのルーチンのいずれかを使用する場合 (「call_argv」を除く)、プログラマは
Perl スタック。 これらには、次のマクロと関数が含まれます。
dSP
SP
プッシュマーク()
戻す
スパガイン
ENTER
SAVETMPS
FREETMPS
離れる
XPUSH*()
ポップ*()
C から Perl への呼び出し規則の詳細については、perlcall を参照してください。
パッティング a C 値 on パール スタック
多くのオペコード (これは内部 Perl スタック マシンの基本的な操作です) が配置されます。
スタック上の SV*。 ただし、最適化により、対応する SV は (通常は)
毎回再作成されます。 オペコードは、特別に割り当てられた SV (ターゲットs) (として)
必然的に) 常に解放/作成されるわけではありません。
各ターゲットは XNUMX 回だけ作成されます (ただし、下記の「スクラッチパッドと再帰」を参照)。
オペコードが整数、倍精度、または文字列をスタックに置く必要がある場合、単に
その対応する部分 ターゲット そして、 ターゲット スタック上にあります。
このターゲットをスタックに置くマクロは「PUSHTARG」で、一部のプログラムで直接使用されます。
オペコードだけでなく、「(X)PUSH[iunp]」を介して間接的に使用する他の無数のオペコードでも使用されます。
ターゲットは再利用されるため、ターゲットに複数の値をプッシュする場合は注意が必要です。
スタック。 次のコードはあなたが思っているようなことをしません:
XPUHi(10);
XPUHi(20);
これは、「"TARG" を 10 に設定し、"TARG" へのポインタをスタックにプッシュし、"TARG" を設定する」と解釈されます。
20 までは、「TARG」へのポインタをスタックにプッシュします。操作の最後に、スタックは
値 10 と 20 は含まれていませんが、実際には「TARG」への XNUMX つのポインタが含まれています。
20に設定しました。
複数の異なる値をプッシュする必要がある場合は、「(X)PUSH」を使用する必要があります。
マクロを使用するか、新しい「m(X)PUSH[iunp]」マクロを使用しますが、いずれも「TARG」を使用しません。
「(X)PUSHs」マクロは単に SV* をスタックにプッシュします。これは、「XSUB と
新しい「m(X)PUSH[iunp]」マクロは、多くの場合、「mortal」である必要があります。
これは、(「(X)PUSHmortal」経由で) 新しい定命の者を作成することで少し簡単に達成できます。
それをスタックにプッシュします (「mXPUSH[iunp]」の場合は必要に応じて拡張します)
マクロ)、その値を設定します。 したがって、例を「修正」するためにこれを書くのではなく、
上記:
XPUSHs(sv_2mortal(新しいSViv(10)))
XPUSHs(sv_2mortal(新しいSViv(20)))
単純に次のように書くことができます。
mXPUSHi(10)
mXPUSHi(20)
関連したメモとして、「(X)PUSH[iunp]」を使用する場合は、「dTARG」が必要になります。
「*PUSH*」マクロがローカル変数を使用できるように変数を宣言します。
「ターグ」。 「dTARGET」および「dXSTARG」も参照してください。
スクラッチパッド
SV がいつになるのかという疑問は残ります。 ターゲットオペコード用の が作成されます。 の
答えは、それらは現在のユニット、つまりサブルーチンまたはファイル(オペコードの場合)のときに作成されるということです。
サブルーチン外のステートメントの場合)-- コンパイルされます。 この間、特別な匿名
現在のユニットのスクラッチパッドと呼ばれる Perl 配列が作成されます。
スクラッチパッドには、現在の単位の語彙であり、ターゲットとなる SV が保持されます。
オペコード。 この文書の以前のバージョンでは、SV が生存していると推測できると記載されていました。
スクラッチパッド上でそのフラグを確認することで、字句には「SVs_PADMY」が設定されており、 ターゲット持っている
「SVs_PADTMP」を設定します。 しかし、これは決して完全に真実ではありません。 「SVs_PADMY」は
どのパッドにも存在しない変数。その間 ターゲット「SVs_PADTMP」が設定されています。
パッドに存在したことのない変数に設定することもできますが、それでも次のように動作します。
ターゲットs. Perl 5.21.5 以降、「SVs_PADMY」フラグは使用されなくなり、0 として定義されます。
「SvPADMY()」は「SVs_PADTMP」のないものに対して true を返すようになりました。
OPとの対応 ターゲットs は 1 対 1 ではありません。 コンパイル時のさまざまな OP
ユニットのツリーは、予想されるものと矛盾しない場合は、同じターゲットを使用できます。
一時的な人生。
スクラッチパッド と 再帰
実際、コンパイル済みユニットにスクラッチパッド AV へのポインタが含まれるかどうかは 100% 真実ではありません。
実際、これには (最初は) XNUMX つの要素の AV へのポインタが含まれており、この要素は
スクラッチパッドAV。 なぜ追加の間接レベルが必要なのでしょうか?
答えは 再帰、 そして多分 スレッド。 これらはどちらも複数の実行を作成する可能性があります
同じサブルーチンに入るポインター。 サブルーチンの子の場合は、上書きしないでください。
サブルーチンの親の一時的なもの (その存続期間は子への呼び出しをカバーします)、
親と子は異なるスクラッチパッドを持つ必要があります。 ( 語彙はこうあるべきです
とにかく別れる!)
したがって、各サブルーチンはスクラッチパッドの配列 (長さ 1) を持って生まれます。 にエントリーするたびに、
サブルーチンでは、現在の再帰の深さが次の値を超えていないことがチェックされます。
この配列の長さ。長ければ、新しいスクラッチパッドが作成され、配列にプッシュされます。
この ターゲットこのスクラッチパッド上の は「undef」ですが、すでに正しいとマークされています
フラグ。
メモリ 割り当て
割り当て
Perl API 関数で使用するすべてのメモリは、
このセクションで説明するマクロ。 マクロは、間に必要な透明性を提供します。
Perl 内で使用される実際の malloc 実装の違い。
Perl とともに配布される malloc のバージョンを有効にすることをお勧めします。 それ
割り当て要求を満たすために、さまざまなサイズの未割り当てメモリのプールを保持します。
もっと早く。 ただし、一部のプラットフォームでは、偽の malloc または free エラーが発生する可能性があります。
次の XNUMX つのマクロは、最初にメモリを割り当てるために使用されます。
Newx(ポインタ, 数値, 型);
Newxc(ポインタ、数値、型、キャスト);
Newxz(ポインタ, 数値, 型);
最初の引数「ポインター」は、新しく追加されたオブジェクトを指す変数の名前にする必要があります。
割り当てられたメモリ。
XNUMX 番目と XNUMX 番目の引数「number」と「type」は、指定されたタイプの数を指定します。
のデータ構造を割り当てる必要があります。 引数「type」は「sizeof」に渡されます。 の
「Newxc」の最後の引数「cast」は、「pointer」引数が異なる場合に使用する必要があります
「type」引数から。
「Newx」および「Newxc」マクロとは異なり、「Newxz」マクロは「memzero」を呼び出してすべてをゼロにします。
新しく割り当てられたメモリ。
再割り当て
Renew(ポインタ、数値、型);
Renewc(ポインタ、数値、型、キャスト);
セーフフリー(ポインタ)
これら XNUMX つのマクロは、メモリ バッファ サイズを変更するか、メモリの一部を解放するために使用されます。
もっと長く必要です。 「Renew」と「Renewc」の引数は、「New」と「Newc」の引数と一致します。
「マジック クッキー」引数が必要ないという例外があります。
移動する
Move(ソース、宛先、番号、タイプ);
Copy(ソース、宛先、番号、型);
ゼロ(宛先、数値、型);
これら XNUMX つのマクロは、以前に割り当てられたメモリを移動、コピー、またはゼロにするために使用されます。 の
「source」引数と「dest」引数は、ソースと宛先の開始点を指します。 パール
「type」データ構造のサイズの「number」インスタンスを移動、コピー、またはゼロアウトします。
(「sizeof」関数を使用)。
PerlIO
Perl の最新の開発リリースでは、Perl の削除が実験されています。
「通常の」標準 I/O スイートに依存し、他の stdio 実装を許可します。
利用される。 これには、新しい抽象化レイヤーを作成し、それを呼び出すものが含まれます。
Perl でコンパイルされた stdio の実装。 すべての XSUB は次の関数を使用する必要があります。
PerlIO 抽象化レイヤーを使用し、stdio がどのようなものであるかを想定しません。
使用されています。
PerlIO 抽象化の完全な説明については、perlapio を参照してください。
コンパイルされた コード
Code ツリー
ここでは、コードが Perl によって変換される内部形式について説明します。 簡単なことから始めましょう
例:
$a = $b + $c;
これは、次のようなツリーに変換されます。
に割り当てます
/\
+$a
/\
$b $c
(ただし、少し複雑になります)。 このツリーは Perl がコードを解析する方法を反映していますが、
実行順序とは関係ありません。 追加の「スレッド」が通過します
ノードの実行順序を示すツリーのノード。 私たちの簡略化された
上記の例は次のようになります。
$b ---> $c ---> + ---> $a ---> 割り当て先
しかし、「$a = $b + $c」の実際のコンパイル ツリーでは異なります。一部のノード 最適化
離れて。 必然的に、実際のツリーには単純化されたツリーよりも多くのノードが含まれますが、
たとえば、実行順序はこの例と同じです。
調べる ツリー
Perl をデバッグ用にコンパイルしている場合 (通常は、
"Configure" コマンド ライン)、コマンド ラインで "-Dx" を指定すると、コンパイルされたツリーを調べることができます。
Perlコマンドライン。 出力はノードごとに数行かかり、「$b+$c」の場合は次のようになります。
この:
5 タイプ = 追加 ===> 6
ターゲット = 1
フラグ = (スカラー,キッズ)
{
TYPE = null ===> (4)
(rv2svでした)
フラグ = (スカラー,キッズ)
{
3 タイプ = gvsv ===> 4
フラグ = (スカラー)
GV = メイン::b
}
}
{
TYPE = null ===> (5)
(rv2svでした)
フラグ = (スカラー,キッズ)
{
4 タイプ = gvsv ===> 5
フラグ = (スカラー)
GV = メイン::c
}
}
このツリーには 5 つのノード (「TYPE」指定子ごとに 3 つ) があり、そのうち XNUMX つだけが最適化されていません。
(左列の数字ごとに XNUMX つ)。 指定されたノードの直接の子が対応します
同じインデントレベルにある「{}」のペアなので、このリストはツリーに対応します。
加えます
/\
ヌルヌル
| |
gvsv gvsv
実行順序は「===>」マークで示されており、「3 4 5 6」となります(ノード6はそうではありません)。
上のリストに含まれています)、つまり、「gvsv gvsv add anything」。
これらの各ノードは、Perl コア内の基本的な操作である op を表します。 の
各操作を実装するコードは、 pp*.c ファイル。 関数
タイプ「gvsv」の操作を実装するのは「pp_gvsv」などです。 上のツリーが示すように、
異なる演算には異なる数の子の数があります。「add」は二項演算子です。
と期待しており、XNUMX人の子供もいます。 さまざまな数に対応するため、
子、op データ構造にはさまざまなタイプがあり、それらは次のようにリンクされています。
違う方法。
最も単純なタイプの op 構造は「OP」です。これには子がありません。 単項演算子、
「UNOP」には XNUMX つの子があり、これは「op_first」フィールドによってポイントされます。 二項演算子
(「BINOP」) には「op_first」フィールドだけでなく「op_last」フィールドもあります。 最も
複合型の操作は「LISTOP」であり、任意の数の子を持ちます。 この場合、
最初の子は「op_first」によってポイントされ、最後の子は「op_last」によってポイントされます。 中の子どもたちは、
最初の子からの「OpSIBLING」ポインタを繰り返したどることで、間の値を見つけることができます。
最後まで(ただし、以下を参照)。
他にもいくつかの操作タイプがあります。「PMOP」は正規表現を保持しますが、
「LOOP」には子がある場合とない場合があります。 「op_children」フィールドが非
ゼロの場合、「LISTOP」のように動作します。 「UNOP」が実際には「null」である場合、問題はさらに複雑になります。
op の最適化 (「コンパイル パス 2: コンテキストの伝播」を参照) の後でも、
以前のタイプに従って子を作成します。
最後に、「LOGOP」、つまり論理演算があります。 「LISTOP」と同様に、これには XNUMX つ以上の子があり、
ただし、「op_last」フィールドがないため、「op_first」の後に続く必要があります。
「OpSIBLING」自体を連鎖させて最後の子を見つけます。 代わりに「op_other」フィールドがあります。
以下で説明する「op_next」フィールドに相当し、代替フィールドを表します。
実行パス。 「and」、「or」、「?」などの演算子は「LOGOP」です。 一般に、
「op_other」は、「LOGOP」の直接の子を指すことはできません。
バージョン 5.21.2 以降、実験的な定義「-DPERL_OP_PARENT」を使用して構築された Perl
各操作に追加のブール フラグ「op_moresib」を追加します。 設定されていない場合、これは次のことを示します。
これは「OpSIBLING」チェーンの最後の操作です。 これにより、
親操作を指す最後の兄弟。 このビルドでは、そのフィールドの名前も変更されます
「op_sibparent」は共同の役割を反映します。 マクロ OpSIBLING(o) は、この特殊な機能をラップします。
最後の兄弟では常に NULL を返します。このビルドでは、op_parent(o)
関数を使用すると、任意の操作の親を見つけることができます。 したがって、上位互換性のために、
"op_sibling" に直接アクセスするのではなく、常に OpSIBLING(o) マクロを使用する必要があります。
ツリーを調べるもう XNUMX つの方法は、B::Concise などのコンパイラ バックエンド モジュールを使用することです。
コンパイル パス 1: チェック ルーチン
ツリーはコンパイラによって作成されますが、 ヤック コードはそれに構造を与えます
認識します。 以来 ヤック Perl コンパイルの最初のパスも同様にボトムアップで動作します。
Perl 開発者にとってこのパスが興味深いのは、一部の最適化が可能であることです。
このパスで実行されます。 これは、いわゆる「チェック ルーチン」による最適化です。 の
ノード名と対応するチェック ルーチンの対応については、「
オペコード.pl (このファイルを変更する場合は、必ず「make regen_headers」を実行してください)。
チェック ルーチンは、実行を除いてノードが完全に構築されたときに呼び出されます。
注文スレッド。 現時点では、現在構築されているものへのバックリンクはありません。
ノードでは、最上位ノードに対して、解放や解放などのほとんどの操作を行うことができます。
その上/下に新しいノードを作成します。
チェック ルーチンは、ツリーに挿入されるべきノードを返します (最上位の場合、
レベル ノードが変更されていない場合、チェック ルーチンはその引数を返します)。
慣例により、チェック ルーチンには「ck_*」という名前が付けられます。 通常は「new*OP」から呼び出されます。
サブルーチン (または「変換」) (これらは次に呼び出されます) パーリー.y).
コンパイル パス 1a: 定数 折り畳み式の
チェック ルーチンが呼び出された直後に、返されたノードが次の状態であるかどうかがチェックされます。
コンパイル時の実行可能ファイル。 そうであれば(値が一定であると判断される場合)、すぐに
実行され、 定数 対応するサブツリーの「戻り値」を持つノードは、
代わりに代用されました。 サブツリーが削除されます。
定数フォールディングが行われていない場合は、実行順序スレッドが作成されます。
コンパイル パス 2: コンテキスト 伝播
コンパイル ツリーの一部のコンテキストがわかっている場合、それはコンパイル ツリーを通じて伝播されます。
木。 現時点では、コンテキストには 5 つの値を含めることができます (実行時コンテキストの場合は 2 つの値ではなく)。
void、ブール、スカラー、リスト、左辺値。 パス 1 とは対照的に、このパスは
上から下に処理されます。ノードのコンテキストがその子のコンテキストを決定します。
この時点で、追加のコンテキスト依存の最適化が実行されます。 この時点から
コンパイル ツリーに (「スレッド」ポインタを介した) 逆参照が含まれると、ノードを
自由()今。 この段階で最適化されたアウェイ ノードを許可するには、そのようなノードは次のようになります。 ヌル()修飾された
自由()(つまり、タイプが OP_NULL に変更されます)。
コンパイル パス 3: のぞき穴 最適化
サブルーチン (または「eval」またはファイル) のコンパイル ツリーが作成された後、
コードの追加のパスオーバーが実行されます。 このパスはトップダウンでもボトムアップでもありません。
ただし、実行順序は異なります (条件文の追加の複雑さはあります)。
この段階で実行される最適化には、パスの場合と同じ制限が適用されます。
2.
のぞき穴の最適化は、グローバル変数が指す関数を呼び出すことによって行われます。
「PL_ピープ」。 デフォルトでは、「PL_peepp」はグローバル変数が指す関数を呼び出すだけです。
変数「PL_rpeepp」。 デフォルトでは、いくつかの基本的な操作の修正と最適化が実行されます。
実行順序演算チェーンに沿って、各サイドチェーンに対して「PL_rpeepp」を再帰的に呼び出します。
操作の数 (条件文からの結果)。 拡張機能により追加の最適化が提供される場合があります。
フィックスアップは、次のようにサブルーチンごとまたは再帰ステージのいずれかにフックします。
静的peep_t prev_peepp;
static void my_peep(pTHX_ OP *o)
{
/* ここにサブルーチンごとのカスタム最適化が入ります */
prev_peepp(aTHX_ o);
/* サブルーチンごとのカスタム最適化もここで行うことができます */
}
ブート:
prev_peepp = PL_peepp;
PL_peep = my_peep;
静的peep_t prev_rpeepp;
static void my_rpeep(pTHX_ OP *o)
{
OP *orig_o = o;
for(; o; o = o->op_next) {
/* ここにカスタムの操作ごとの最適化が入ります */
}
prev_rpeepp(aTHX_orig_o);
}
ブート:
prev_rpeepp = PL_rpeepp;
PL_rpeep = my_rpeep;
プラガブル ルノー
コンパイル ツリーは runops 関数で実行されます。 runops 関数は XNUMX つあります。
run.c または ダンプ.c。 「Perl_runops_debug」は DEBUGGING で使用され、
それ以外の場合は、「Perl_runops_standard」が使用されます。 の実行を細かく制御するため、
コンパイル ツリーでは、独自の runops 関数を提供できます。
おそらく、既存の runops 関数の XNUMX つをコピーし、目的に合わせて変更するのが最善です。
ニーズ。 次に、XS ファイルの BOOT セクションに次の行を追加します。
PL_runops = my_runops;
プログラムを可能な限り高速に実行できるように、この関数は可能な限り効率的である必要があります。
可能。
コンパイル時 スコープ フック
Perl 5.14 では、次を使用してコンパイル時の字句スコープ メカニズムにフックすることができます。
「Perl_blockhook_register」。 これは次のように使用されます。
STATIC void my_start_hook(pTHX_ int full);
STATIC BHK my_hooks;
ブート:
BhkENTRY_set(&my_hooks, bhk_start, my_start_hook);
Perl_blockhook_register(aTHX_ &my_hooks);
これにより、すべての字句のコンパイルの開始時に「my_start_hook」が呼び出されるようになります。
範囲。 使用可能なフックは次のとおりです。
「void bhk_start(pTHX_ int full)」
これは、新しい字句スコープを開始した直後に呼び出されます。 次のような Perl コードに注意してください
if ($x) { ... }
1 つのスコープを作成します。最初のスコープは "(" で始まり、"full == XNUMX" で始まり、XNUMX 番目のスコープは "(" で始まります) で始まります。
「{」の部分に「full == 0」があります。 どちらも「}」で終わるため、「start」と「start」を呼び出します。
「pre/post_end」が一致します。 このフックによって保存スタックにプッシュされたものはすべて、
スコープが終了する直前にポップされます (実際には、「pre_」フックと「post_end」フックの間)。
"void bhk_pre_end(pTHX_ OP **o)"
これは、字句スコープの最後、スタックを巻き戻す直前に呼び出されます。 o is
スコープを表す optree のルート。 ダブルポインタなので次のことができます
必要に応じてOPを交換してください。
"void bhk_post_end(pTHX_ OP **o)"
これは、スタックを巻き戻した直後、字句スコープの最後で呼び出されます。 o として
その上。 「pre_」と「post_end」への呼び出しがネストされる可能性があることに注意してください。
保存スタック上にある文字列 eval を呼び出すものです。
"void bhk_eval(pTHX_ OP *const o)"
これは、「eval STRING」、「do FILE」、「require」のコンパイルを開始する直前に呼び出されます。
または、評価が設定された後に「使用」します。 o は評価を要求した OP であり、
通常は「OP_ENTEREVAL」、「OP_DOFILE」、または「OP_REQUIRE」になります。
フック関数を作成したら、それを配置するための「BHK」構造体が必要です。
一度登録すると解放する方法がないため、静的に割り当てる必要があります。 の
関数ポインタは、「BhkENTRY_set」マクロを使用してこの構造体に挿入する必要があります。
これにより、どのエントリが有効であるかを示すフラグも設定されます。 割り当てる必要がある場合
何らかの理由で「BHK」が動的に変化するため、開始する前に必ずゼロにしてください。
一度登録すると、これらのフックをオフにするメカニズムはないため、必要に応じて
これは自分で行う必要があります。 "%^H" にエントリを入力するのがおそらく最良の方法であるため、
効果は語彙的にスコープされます。 ただし、「BhkDISABLE」を使用することも可能です。
エントリのオンとオフを一時的に切り替える「BhkENABLE」マクロ。 あなたも知っておくべきです
一般的に、拡張機能が実行される前に、少なくとも XNUMX つのスコープが開かれているはずです。
ロードされているため、一致する「開始」を持たない「pre/post_end」ペアがいくつか表示されます。
調べる 内部 データ 構造 "ごみ" 機能
デバッグを容易にするために、ソース ファイル ダンプ.c を生成する多くの関数が含まれています。
内部データ構造のフォーマットされた出力。
これらの関数の中で最もよく使用されるのは「Perl_sv_dump」です。 SVのダンプに使用されます。
AV、HV、CV。 「Devel::Peek」モジュールは「sv_dump」を呼び出してデバッグ出力を生成します
Perl スペースからのものなので、そのモジュールのユーザーはすでにその形式に精通しているはずです。
「Perl_op_dump」は、「OP」構造またはその派生物のいずれかをダンプするために使用できます。
「perl -Dx」のような出力が生成されます。 実際、「Perl_dump_eval」はメインルートをダンプします。
評価されるコードの名前。「-Dx」とまったく同じです。
その他の便利な関数は、「GV」を op ツリーに変える「Perl_dump_sub」です。
「Perl_dump_packsubs」は、次のようなパッケージ内のすべてのサブルーチンで「Perl_dump_sub」を呼び出します。
so: (ありがたいことに、これらはすべて xsub であるため、op ツリーはありません)
(gdb) print Perl_dump_packsubs(PL_defstash)
SUB 属性::ブートストラップ = (xsub 0x811fedc 0)
サブユニバーサル::can = (xsub 0x811f50c 0)
サブユニバーサル::isa = (xsub 0x811f304 0)
サブユニバーサル::バージョン = (xsub 0x811f7ac 0)
SUB DynaLoader::boot_DynaLoader = (xsub 0x805b188 0)
「Perl_dump_all」は、スタッシュと op ツリー内のすべてのサブルーチンをダンプします。
主根。
認定条件 の試合に 通訳 と 並行性 。
経歴 と PERL_IMPLICIT_CONTEXT
Perl インタプリタは閉じたボックスとみなすことができます。これにはコードを供給するための API があり、
それ以外の場合は、何かを実行させるだけでなく、それ自身で使用するための関数もあります。 これは臭いがする
これはオブジェクトによく似ており、複数のオブジェクトを持つことができるように Perl を構築する方法があります。
インタープリター。XNUMX つのインタープリターは C 構造体として、または内部で表現されます。
スレッド固有の構造。 これらの構造には、すべてのコンテキストとその状態が含まれています。
通訳。
XNUMX つのマクロは、主要な Perl ビルド フレーバーである MULTIPLICITY を制御します。 MULTIPLICITY ビルドには、
すべてのインタープリターの状態をパッケージ化した C 構造体。 多重度が有効な Perl を使用すると、
PERL_IMPLICIT_CONTEXT も通常定義されており、これにより、
XNUMX つのデータ構造すべてを表す「hidden」最初の引数。 多重性により、
マルチスレッド Perl が可能 (マクロに関連する ithreads スレッド モデルを使用)
USE_ITHREADS。)
他の XNUMX つの「カプセル化」マクロは、PERL_GLOBAL_STRUCT と PERL_GLOBAL_STRUCT_PRIVATE です。
(後者は前者をオンにし、前者は MULTIPLICITY をオンにします。)
PERL_GLOBAL_STRUCT を使用すると、Perl のすべての内部変数が単一の変数内にラップされます。
グローバル構造体、構造体 perl_vars、(グローバル) &PL_Vars または PL_VarsPtr としてアクセス可能
function Perl_GetVars()。 PERL_GLOBAL_STRUCT_PRIVATE はさらに一歩進んで、次のようなものがあります。
まだ単一の構造体です ( メイン() ヒープまたはスタックから)しかし、
それを指すグローバル データ シンボルはありません。 どちらの場合も、グローバル構造体は次のようにする必要があります。
の最初のものとして初期化されます メイン() Perl_init_global_struct() と
それに応じてその後にそれを取り壊します perl_free() Perl_free_global_struct()は、以下を参照してください
ミニパールメイン.c 使用方法の詳細については、 コーディングで「dVAR」を使用する必要がある場合もあります。
グローバル変数を使用する場合は、「グローバル変数を宣言」してください。 dTHX がこれを行います
自動的に。
非定数データがあるかどうかを確認するには、BSD (または GNU) 互換の「nm」を使用できます。
nm libperl.a | grep -v ' [TURtr] '
「D」または「d」記号 (場合によっては「C」または「c」) が表示される場合は、非定数データがあります。
「grep」によって削除された記号は次のとおりです。「Tt」は次のとおりです。 클라우드 기반 AI/ML및 고성능 컴퓨팅을 통한 디지털 트윈의 기초 – Edward Hsu, Rescale CPO 많은 엔지니어링 중심 기업에게 클라우드는 R&D디지털 전환의 첫 단계일 뿐입니다. 클라우드 자원을 활용해 엔지니어링 팀의 제약을 해결하는 단계를 넘어, 시뮬레이션 운영을 통합하고 최적화하며, 궁극적으로는 모델 기반의 협업과 의사 결정을 지원하여 신제품을 결정할 때 데이터 기반 엔지니어링을 적용하고자 합니다. Rescale은 이러한 혁신을 돕기 위해 컴퓨팅 추천 엔진, 통합 데이터 패브릭, 메타데이터 관리 등을 개발하고 있습니다. 이번 자리를 빌려 비즈니스 경쟁력 제고를 위한 디지털 트윈 및 디지털 스레드 전략 개발 방법에 대한 인사이트를 나누고자 합니다. 、またはコードの「Rr」は 読んだ-
の (const) データ、「U」は、外部シンボルを参照します。
テスト t/porting/libperl.t 「libperl.a」に対してこの種のシンボルの健全性チェックを行います。
下位互換性の理由から、PERL_GLOBAL_STRUCT だけを定義しても実際には非表示になりません。
大きなグローバル構造体内のすべてのシンボル: 一部の PerlIO_xxx vtable は表示されたままになります。 の
次に、PERL_GLOBAL_STRUCT_PRIVATE はすべてを非表示にします (PERLIO_FUNCS_DECL がどのように使用されるかを参照してください)。
これには明らかに、Perl の内部関数をいずれかのサブルーチンにする方法が必要です。
ある種の構造体を最初の引数として受け取るか、サブルーチンは何も受け取りません。
最初の引数。 これら XNUMX つのまったく異なる方法でインタプリタを構築できるようにするには、
Perl ソースは (他の多くの状況と同様に) マクロを多用し、
サブルーチンの命名規則。
最初の問題: どの関数をパブリック API 関数にするか、どの関数をパブリック API 関数にするかを決定する
プライベート。 名前が「S_」で始まるすべての関数はプライベートです (「S」は「secret」または
"静的")。 他のすべての関数は「Perl_」で始まりますが、関数が始まるからといって
「Perl_」は、それが API の一部であることを意味するものではありません。 (「内部関数」を参照してください。)
最も簡単な方法 確か 関数は API の一部であり、perlapi でそのエントリを検索します。 もし
これは perlapi に存在し、API の一部です。 そうでなければ、そしてそうあるべきだとあなたが思うなら
(つまり、拡張機能に必要です)、そう思う理由を説明するメールを perlbug 経由で送信してください
あるべきです。
XNUMX 番目の問題: 同じサブルーチンの宣言と呼び出しを行うための構文が必要です。
最初の引数として構造体を渡すことも、何も渡さないこともできます。 これを解決するには、
サブルーチンは、特定の方法で名前が付けられ、宣言されます。 これが典型的な始まりです
Perl 内部で使用される静的関数:
静的ボイド
S_incline(pTHX_ char *s)
STATIC は C では「静的」になり、一部の構成では何も #define されない場合があります。
未来。
パブリック関数 (つまり、内部 API の一部ですが、必ずしも使用が許可されているわけではありません)
拡張子内) は次のように始まります。
ボイド
Perl_sv_setiv(pTHX_ SV* dsv、IV 番号)
「pTHX_」は、多数のマクロのうちの XNUMX つです ( perl.h) の詳細を非表示にします。
通訳者のコンテキスト。 THX は、場合によっては「糸」、「これ」、または「物」を表します。
(いいえ、ジョージ ルーカスは関与していません。:-) 最初の文字は、
pロトタイプ、「a」 a議論、または「d」 d宣言なので、「pTHX」、「aTHX」、「dTHX」があります。
およびその亜種。
PERL_IMPLICIT_CONTEXT を設定するオプションを使用せずに Perl をビルドする場合、最初のオプションはありません。
インタプリタのコンテキストを含む引数。 pTHX_ マクロの末尾のアンダースコア
マクロ展開にはコンテキスト引数の後にコンマが必要であることを示します。
引数がそれに続きます。 PERL_IMPLICIT_CONTEXT が定義されていない場合、pTHX_ は無視され、
サブルーチンは追加の引数を取るようにプロトタイプ化されていません。 マクロの形式
末尾のアンダースコアなしは、追加の明示的な引数がない場合に使用されます。
コア関数が別の関数を呼び出すときは、コンテキストを渡す必要があります。 これは通常、次のように隠されています
マクロ。 「sv_setiv」について考えてみましょう。 これは次のように展開されます。
#ifdef PERL_IMPLICIT_CONTEXT
#define sv_setiv(a,b) Perl_sv_setiv(aTHX_ a, b)
/* 可変長引数関数ではこれを行うことはできません。以下を参照してください */
#その他
#define sv_setiv Perl_sv_setiv
#endif
これはうまく機能し、XS 作成者は喜んで次のように書くことができることを意味します。
sv_setiv(foo, bar);
Perl をコンパイルできるすべてのモードで引き続き動作します。
ただし、マクロは、
引数の数は事前にわかっています。 代わりに、それらを完全に詳しく説明する必要があります。
最初の引数として「aTHX_」を渡します (Perl コアは、次のような関数でこれを行う傾向があります)
Perl_warner)、またはコンテキストフリー バージョンを使用してください。
Perl_warner のコンテキストフリー バージョンは Perl_warner_nocontext と呼ばれ、
追加の引数。 代わりに dTHX を実行します。 スレッドローカルストレージからコンテキストを取得します。
拡張機能がソース互換性を取得できるように「#define warner Perl_warner_nocontext」します。
パフォーマンスのコスト。 (引数を渡すことは、スレッドローカルから取得するよりも安価です
ストレージ。)
Perl ヘッダー/ソースを参照するときは、[pad]THXx を無視できます。 それらは厳密に言うと、
コア内で使用します。 拡張機能とエンベッダーは、[pad]THX のみを認識する必要があります。
So 何 が起こった 〜へ dTHR?
「dTHR」は、古いスレッド モデルをサポートするために Perl 5.005 で導入されました。古いスレッド
モデルは「THX」メカニズムを使用してコンテキスト ポインターを渡すようになりました。そのため、「dTHR」は使用されません。
もう役に立ちます。 Perl 5.6.0 以降では、ソースの下位互換性のためにまだこの機能が残っています。
ただし、それは no-op であると定義されています。
認定条件 do I つかいます を この in 拡張子?
Perl が PERL_IMPLICIT_CONTEXT を使用してビルドされている場合、拡張機能は、
Perl API は、何らかの方法で初期コンテキスト引数を渡す必要があります。 キッカーはあなたです
Perl がコンパイルしていない場合でも拡張機能がコンパイルされるような方法で記述する必要があります。
PERL_IMPLICIT_CONTEXT を有効にしてビルドされています。
これを行うには 3 つの方法があります。まず、簡単ですが非効率な方法です。
デフォルト、拡張機能とのソース互換性を維持するため: いつでも XSUB.h is
#include では、aTHX マクロと aTHX_ マクロを再定義して、
コンテクスト。 したがって、次のようなものになります。
sv_setiv(sv, num);
PERL_IMPLICIT_CONTEXT が有効な場合、拡張機能内の は次のように変換されます。
Perl_sv_setiv(Perl_get_context(), sv, num);
または、そうでない場合は次のようになります。
Perl_sv_setiv(sv, num);
これを取得するために拡張機能で何か新しいことを行う必要はありません。 Perlライブラリ以来
は、大阪で Perl_get_context()、すべてうまくいきます。
XNUMX 番目のより効率的な方法は、Foo.xs に次のテンプレートを使用することです。
#define PERL_NO_GET_CONTEXT /* 効率性が必要です */
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
STATIC void my_private_function(int arg1, int arg2);
静的ボイド
my_private_function(int arg1, int arg2)
{
dTHX; /* コンテキストを取得 */
...多くの Perl API 関数を呼び出します ...
}
[...など...]
モジュール = Foo パッケージ = Foo
/* 一般的な XSUB */
ボイド
my_xsub(引数)
整数引数
CODE:
my_private_function(arg, 10);
拡張機能の通常の記述方法からの変更点は 2 つだけであることに注意してください。
Perl ヘッダーを含める前に「#define PERL_NO_GET_CONTEXT」を追加し、その後に
「dTHX;」 Perl API を呼び出すすべての関数の開始時に宣言します。 (あなたはそうするだろう
C コンパイラは、
XSUB には変更は必要ありません。
なぜなら、 XS() マクロが暗黙的なコンテキストで渡すように正しく定義されている場合、
必要です。
XNUMX 番目のさらに効率的な方法は、Perl の内部でどのように行われるかを模倣することです。
#define PERL_NO_GET_CONTEXT /* 効率性が必要です */
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
/* pTHX_ は Perl API を呼び出す関数にのみ必要です */
STATIC void my_private_function(pTHX_ int arg1, int arg2);
静的ボイド
my_private_function(pTHX_ int arg1, int arg2)
{
/* dTHX; THX は引数であるため、ここでは必要ありません */
... Perl API 関数を呼び出す ...
}
[...など...]
モジュール = Foo パッケージ = Foo
/* 一般的な XSUB */
ボイド
my_xsub(引数)
整数引数
CODE:
my_private_function(aTHX_ arg, 10);
この実装では、関数呼び出しを使用してコンテキストをフェッチする必要はありません。
常に追加の引数として渡されます。 シンプルさまたは効率性のニーズに応じて、
前の XNUMX つのアプローチを自由に組み合わせることができます。
自分で「pTHX」の後にカンマを追加しないでください。常にマクロの形式を使用してください。
明示的な引数を取る関数のアンダースコア、または引数のない形式
明示的な引数のない関数の場合。
「-DPERL_GLOBAL_STRUCT」を使用して Perl をコンパイルしている場合は、「dVAR」定義が必要です
Perl グローバル変数 (「 perlvars.h or globvar.sym) は関数でアクセスされます
「dTHX」は使用されません(「dTHX」には必要に応じて「dVAR」が含まれます)。 人は気づく
「dVAR」が必要なのは、上記のコンパイル時定義の場合のみです。それ以外の場合は、Perl グローバル
変数はそのまま表示されます。
すべき I do 何でも 特別 if I コール パール from の試合に スレッド?
あるスレッドでインタプリタを作成し、別のスレッドでそれらを呼び出すと、
Perl 自身のスレッド ローカル ストレージ (TLS) スロットが正しく初期化されていることを確認する必要があります。
それらのスレッドのそれぞれ。
「perl_alloc」および「perl_clone」API 関数は、TLS スロットを自動的に設定します。
彼らが作成したインタプリタなので、
インタプリタは常に、それを作成したのと同じスレッドでアクセスされ、そのスレッドはアクセスされません。
その後、他のインタープリターを作成するか呼び出します。 そうでない場合は、次のようにする必要があります。
Perl API の関数を呼び出す前に、スレッドの TLS スロットを設定します。
特定の通訳者。 これは、その中で「PERL_SET_CONTEXT」マクロを呼び出すことによって行われます。
最初に行うこととしてスレッドを作成します。
/* some_perl で他のことを行う前にこれを実行します */
PERL_SET_CONTEXT(some_perl);
...some_perl でのその他の Perl API 呼び出しはここにあります ...
未来 予定 と PERL_IMPLICIT_SYS
PERL_IMPLICIT_CONTEXT がインタプリタのすべてをバンドルする方法を提供するのと同じように、
は自分自身のことを知っており、それを周囲に伝えます。同様に、通訳者が次のことを行えるようにする計画もあります。
実行されている環境について知っているすべてをバンドルします。 これは次の方法で有効になります
PERL_IMPLICIT_SYS マクロ。 現在、Windows 上の USE_ITHREADS でのみ動作します。
これにより、追加のポインター (「ホスト」環境と呼ばれる) を提供できるようになります。
すべてのシステムコール。 これにより、すべてのシステム要素が適切な状態を維持できるようになります。
自身の状態を XNUMX つの C 構造に分解します。 これらは通常の薄いラッパーです
システムコール (「 win32/perllib.c) デフォルトの Perl 実行可能ファイルの場合ですが、それ以上の場合は
野心的なホスト(やりたいと思うようなホスト) フォーク() エミュレーション)必要なすべての追加作業
異なるインタプリタが実際には異なる「プロセス」であるかのように振る舞う場合は、次のようになります。
ページ をご覧ください
Perl エンジン/インタプリタとホストは直交するエンティティです。 XNUMX つまたは
プロセス内の複数のインタプリタと XNUMX つ以上の「ホスト」の間で自由に関連付けられます。
それら。
内部 機能
外部に公開される Perl の内部関数にはすべて接頭辞が付けられます。
XS関数やプログラムで使用する関数と競合しないように「Perl_」で作成
Perlが埋め込まれています。 同様に、すべてのグローバル変数は「PL_」で始まります。 (による
慣例として、静的関数は「S_」で始まります。)
Perl コア (「PERL_CORE」が定義されている) 内では、 または のいずれかを使用して関数を取得できます。
に存在する多数の定義のおかげで、「Perl_」プレフィックスなしで 埋め込み.h。 ご了承ください
拡張コードは 「PERL_CORE」を設定します。 これにより、完全な Perl 内部が公開されます。
新しい Perl リリースごとに XS の破損を引き起こす可能性があります。
ファイル 埋め込み.h から自動的に生成されます 埋め込み.pl と 埋め込み.fnc. 埋め込み.pl また
内部関数のプロトタイピング ヘッダー ファイルを作成し、
ドキュメントやその他多くの断片。 新しいものを追加するときは、
関数をコアに変更するか、既存の関数を変更する場合は、テーブル内のデータを変更します。
埋め込み.fnc 同じように。 そのテーブルのサンプル エントリを次に示します。
Apd |SV** |av_fetch |AV* ar|I32 key|I32 lval
XNUMX 番目の列は戻り値の型、XNUMX 番目の列は名前です。 以降のコラムは、
引数。 最初の列はフラグのセットです。
A この機能は公開APIの一部です。 このような関数にはすべて「d」も必要です。
そうしない人はほとんどいません。
p この関数には「Perl_」という接頭辞が付いています。 つまり、「Perl_av_fetch」として定義されます。
d この関数には、「apidoc」機能を使用したドキュメントがあります。これについては、後で説明します。
XNUMX番。 一部の関数には「d」はありますが、「A」はありません。 ドキュメントは良いです。
その他に使用可能なフラグは次のとおりです。
■ これは静的関数であり、「STATIC S_whatever」として定義され、通常は次のように呼ばれます。
ソース内では「whatever(...)」として記述されます。
n これにはインタプリタコンテキストが必要ないため、定義には「pTHX」がありません。
したがって、呼び出し元は「aTHX」を使用しないことになります。 (「バックグラウンドとPERL_IMPLICIT_CONTEXT」を参照してください。)
r この関数は決して戻りません。 「鳴く」「出る」とその仲間たち。
f この関数は、「printf」スタイルの可変数の引数を受け取ります。引数リスト
次のように「...」で終わる必要があります。
Afprd |void |croak |const char* pat|...
M この機能は実験的な開発 API の一部であり、変更または消滅する可能性があります。
無断で。
o この関数には、「Perl_parse」などを定義する互換性マクロを含めるべきではありません。
「解析」。 これは「Perl_parse」として呼び出す必要があります。
x この関数は Perl コアからエクスポートされません。
m これはマクロとして実装されます。
X この関数は明示的にエクスポートされます。
E この関数は、Perl コアに含まれる拡張機能から参照できます。
b バイナリの下位互換性。 この関数はマクロですが、「Perl_」も持っています。
実装 (エクスポートされる)。
他人
その他については、「embed.fnc」の上部にあるコメントを参照してください。
編集する場合 埋め込み.pl or 埋め込み.fnc、強制的に「make regen_headers」を実行する必要があります。
再構築する 埋め込み.h およびその他の自動生成ファイル。
フォーマット済み 印刷 of 点滴、 UV、 と NV
の代わりに IV、UV、または NVS を印刷している場合は、 標準入出力(3) 次のようなスタイル書式設定コード
%d、%ld、%f、移植性を高めるために次のマクロを使用する必要があります。
IVdf IV (XNUMX 進数)
UVuf XNUMX 進数の UV
XNUMX 進数の UVof UV
UVxf XNUMX 進数の UV
NVef NV %e のような
NVff NV %f のような
NVgf NV %g 様
これらは 64 ビット整数と Long Double を処理します。 例えば:
printf("IV は %"IVdf"\n", iv);
IVdf は、IV の正しい形式に展開されます。
さまざまな「long double」があることに注意してください。Perl はコンパイラが持つものをすべて使用します。
ポインターのアドレスを出力する場合は、UVxf と組み合わせて使用します。 PTR2UV()、%lx は使用しないでください
または %p。
整数へのポインタ と 整数からポインターへ
ポインタのサイズは整数のサイズと必ずしも一致しないため、次のマクロを使用して次のことを行います。
そうです。
PTR2UV(ポインタ)
PTR2IV(ポインタ)
PTR2NV(ポインタ)
INT2PTR(ポインタ型、整数)
例:
IV iv = ...;
SV *sv = INT2PTR(SV*, iv);
と
AV *av = ...;
UV uv = PTR2UV(av);
例外 ハンドリング
XS モジュールで非常に基本的な例外処理を行うためのマクロがいくつかあります。 あなたが持っている
インクルードする前に「NO_XSLOCKS」を定義します XSUB.h これらのマクロを使用できるようにするには:
# NO_XSLOCKS を定義
#include "XSUB.h"
クロークする可能性のあるコードを呼び出す場合は、これらのマクロを使用できますが、クリーンアップを行う必要があります。
Perl に制御を戻す前に。 例えば:
dXCPT; /* 必要な変数を設定します */
XCPT_TRY_START {
code_that_may_croak();
} XCPT_TRY_END
XCPT_CATCH
{
/* ここでクリーンアップを実行します */
XCPT_RETHROW;
}
キャッチされた例外は常に再スローする必要があることに注意してください。 これらを使用して
マクロでは、例外をキャッチして無視することはできません。 しなければならない場合
例外を無視するには、「call_*」関数を使用する必要があります。
上記のマクロを使用する利点は、追加の関数をセットアップする必要がないことです。
「call_*」の場合、これらのマクロを使用した方が「call_*」を使用するよりも高速であることがわかります。
ソース ドキュメント
内部機能を文書化し、自動的に生成する取り組みが進行中です。
これらのリファレンスマニュアル -- perlapi は、すべての機能を詳細に説明するマニュアルの XNUMX つです。
XS ライターが利用できるものです。 perlintern は、
これらの関数は API の一部ではなく、おそらく内部使用のみを目的としています。
ソース ドキュメントは、次のように POD コメントを C ソースに挿入することによって作成されます。
/*
=apidoc sv_setiv の場合
整数を指定された SV にコピーします。 「セット」マジックは扱いません。 見る
C 。
=カット
*/
Perl コアに関数を追加する場合は、ドキュメントを提供してみてください。
後方 互換性
Perl API は時間の経過とともに変化します。 新しい機能が追加されたり、既存のインターフェイスが追加されたりする
機能が変更されます。 「Devel::PPPort」モジュールは、互換性コードを提供しようとします。
これらの変更の一部により、XS 作成者はサポートするときに自分でコーディングする必要がなくなります。
Perl の複数のバージョン。
「Devel::PPPort」はCヘッダーファイルを生成します ppport.h Perl スクリプトとしても実行できます。
引き起こす ppport.h、実行:
perl -MDevel::PPPort -eDevel::PPPort::WriteFile
既存の XS コードをチェックするだけでなく、このスクリプトを使用して互換性を取得することもできます。
「--api-info」コマンド ライン スイッチを使用したさまざまな API 呼び出しの情報。 のために
例:
% perl ppport.h --api-info=sv_magicext
詳細については、「perldoc ppport.h」を参照してください。
Unicode サポート
Perl 5.6.0 では Unicode サポートが導入されました。 ポーターと XS ライターにとって重要なことは、
このサポートを理解し、作成したコードが Unicode を破損しないようにしてください。
データ。
この試験は is ユニコード、 とにかく?
昔の、あまり啓蒙されていない時代には、私たちは皆 ASCII を使用していました。 とにかく、私たちのほとんどはそうでした。
ASCII の大きな問題は、それがアメリカ製であるということです。 いや、実際にはそうではありません
問題; 問題は、これを使用しない人にとっては特に役に立たないことです。
ローマ字。 以前は、特定の言語が独自の言語を固着するということが起こっていました。
シーケンスの上位範囲、128 ~ 255 のアルファベット。
最終的には完全に ASCII ではない多くの亜種ができましたが、その要点は次のとおりです。
基準が失われた。
さらに悪いことに、中国語や日本語のような何百もの言語を使用している場合は、
何千もの文字がある場合、実際にはわずか 256 文字に収めることはできないため、そうする必要がありました。
ASCII のことは完全に忘れて、参照する数値のペアを使用して独自のシステムを構築します。
XNUMX文字に。
これを修正するために、何人かの人々が Unicode, Inc. を設立し、以下を含む新しい文字セットを作成しました。
あなたが思いつくすべてのキャラクターなど。 いくつかの方法があります
これらの文字を表すもので、Perl が使用するものは UTF-8 と呼ばれます。 UTF-8 では、
文字を表す可変バイト数。 Unicode について詳しく学ぶことができ、
perlunicode における Perl の Unicode モデル。
(EBCDIC プラットフォームでは、Perl は代わりに UTF-EBCDIC を使用します。これは、EBCDIC プラットフォームに適合した UTF-8 の形式です。
EBCDIC プラットフォーム。 以下では、UTF-8 についてのみ説明します。 UTF-EBCDIC は UTF-8 に似ていますが、
詳細は異なります。 マクロは違いを隠します。覚えておいてください。
以下に示す特定の数値とビット パターンは、UTF-EBCDIC では異なります。)
認定条件 できる I 認める a UTF-8 ストリング?
あなたはできません。 これは、UTF-8 データは非 UTF-8 データと同様にバイト単位で格納されるためです。 の
Unicode 文字 200、(0 進タイプの場合は 8xCXNUMX) グレーブアクセントが付いた大文字の E は、次のとおりです。
196.172 バイト「vXNUMX」で表されます。 残念ながら、非 Unicode 文字列
"CHRとします。CHR(172)" にもそのバイト列が含まれています。だから、見ただけではわかりません --
これが、Unicode 入力が興味深い問題となる理由です。
一般に、何を扱っているかを知るか、推測する必要があります。 の
API 関数「is_utf8_string」が役に立ちます。 文字列に有効な文字列のみが含まれているかどうかがわかります
UTF-8 文字、および非 UTF-8 文字列が有効な UTF-8 のように見える可能性が高くなります。
文字列の長さが増加すると、非常に急速に非常に小さくなります。 キャラクターごとに、
「isUTF8_CHAR」は、文字列内の現在の文字が有効な UTF-8 であるかどうかを示します。
認定条件 ありません UTF-8 表す Unicode 文字?
前述したように、UTF-8 は文字を格納するために可変バイト数を使用します。
値 0 ~ 127 の文字は、古き良き ASCII と同様に XNUMX バイトに格納されます。
文字 128 は「v194.128」として保存されます。 これは文字 191 まで続きます。
「v194.191」。 ビットがなくなったので (191 は 10111111 進数の XNUMX)、次に進みます。 キャラクター
192は「v195.128」です。 そして、文字 2048 の XNUMX バイトに移動します。「Unicode」
perlunicode の「Encodings」には、これがどのように機能するかの図があります。
UTF-8 文字列を扱っていることがわかっていると仮定すると、最初の文字列の長さがわかります。
その中の文字は「UTF8SKIP」マクロを使用しています。
char *utf = "\305\233\340\240\201";
I32 レン;
len = UTF8SKIP(utf); /* ここでは len は 2 */
utf += レン;
len = UTF8SKIP(utf); /* ここでは len は 3 */
UTF-8 文字列内の文字をスキップするもう 8 つの方法は、「utfXNUMX_hop」を使用することです。
スキップする文字列と文字数。 境界チェックについては自分で行う必要があります。
ただし、安易に使用しないでください。
マルチバイト UTF-8 文字のすべてのバイトには上位ビットが設定されるため、次のようにテストできます。
この文字に対して次のように特別なことを行う必要があります (「UTF8_IS_INVARIANT()」)
バイトが UTF-8 であっても単一バイトとしてエンコードされているかどうかをテストするマクロです)。
U8 *utf;
U8 *utf_end; /* 1 utf が指すバッファを超えています */
紫外線、紫外線。 /* 注意: UV、U8、char ではありません */
STRLENレン。 /* バイト単位の文字の長さ */
if (!UTF8_IS_INVARIANT(*utf))
/* これを UTF-8 として扱う必要があります */
uv = utf8_to_uvchr_buf(utf, utf_end, &len);
ほかに
/* この文字をバイトとして扱ってもOK */
uv = *utf;
この例では、「utf8_to_uvchr_buf」を使用して、
キャラクター; 逆関数「uvchr_to_utf8」は、UV を UTF-8 に入れるために使用できます。
if (!UVCHR_IS_INVARIANT(uv))
/* これを UTF8 として扱う必要があります */
utf8 = uvchr_to_utf8(utf8, uv);
ほかに
/* この文字をバイトとして扱ってもOK */
*utf8++ = uv;
我が国 しなければなりません 状況に応じて上記の関数を使用して文字を UV に変換してください
ここで、UTF-8 文字と非 UTF-8 文字を一致させる必要があります。 UTF-8 をスキップすることはできません
この場合の文字。 これを行うと、ハイビットに一致する能力が失われます。
非 UTF-8 文字。 たとえば、UTF-8 文字列に「v196.172」が含まれている場合、スキップします。
その文字を「」に一致させることはできません。CHR(200)" を UTF-8 以外の文字列に含めます。そのため、これは行わないでください。
(上記の例では不変文字をテストする必要がないことに注意してください。
関数は、整形式の UTF-8 入力に対して機能します。 ただ避けた方が早いだけです
不要な場合の関数のオーバーヘッド。)
認定条件 ありません パール 店舗 UTF-8 文字列?
現在、Perl は UTF-8 文字列と非 UTF-8 文字列を若干異なる方法で処理します。 あ
SV のフラグ「SVf_UTF8」は、文字列が内部で UTF-8 としてエンコードされていることを示します。
これがなければ、バイト値はコードポイント番号になり、その逆も同様です。 この旗はあくまで
SV が「SvPOK」であるか、「SvPV」または
同様のマクロ。 次のマクロを使用して、このフラグを確認および操作できます。
SvUTF8(SV)
SvUTF8_on(sv)
SvUTF8_off(sv)
このフラグは、Perl による文字列の処理に重要な影響を与えます。UTF-8 データがそうでない場合
適切に区別され、正規表現、「length」、「substr」、その他の文字列の処理
操作により望ましくない (間違った) 結果が生じる可能性があります。
問題は、たとえば、UTF-8 としてフラグが設定されていない文字列がある場合に発生します。
UTF-8 である可能性のあるバイト シーケンスが含まれています。特に非 UTF-8 と
UTF-8文字列。
「SVf_UTF8」フラグは PV 値とは別のものであることを決して忘れないでください。 確信する必要があります
SV の操作中に誤って落としてしまうことはありません。 もっと具体的に言えば、あなたは、
これを行うことは期待できません:
SV *sv;
SV *nsv;
STRLENレン。
char *p;
p = SvPV(sv, len);
フロブニケート(p);
nsv = newSVpvn(p, len);
「char*」文字列だけではすべてがわかりません。また、文字列をコピーしたり再構築したりすることはできません。
文字列値をコピーするだけでSV化できます。 古い SV に UTF8 フラグが設定されているかどうかを確認します (After
「SvPV」呼び出し)、それに応じて動作します。
p = SvPV(sv, len);
is_utf8 = SvUTF8(sv);
frobnicate(p, is_utf8);
nsv = newSVpvn(p, len);
if (is_utf8)
SvUTF8_on(nsv);
上記では、「frobnicate」関数は、次のことを認識するように変更されました。
文字列を適切に処理できるように、UTF-8 データを処理しているのではありません。
SV を XS 関数に渡して SV のデータをコピーするだけでは十分ではないため、
UTF8 フラグをコピーします。単に「char *」を XS 関数に渡すのはさらに正しくありません。
完全に一般化するには、perlapi マクロの「DO_UTF8」を使用して、SV 内の文字列が
ようにするには 治療 UTF-8として。 これには、XS 関数の呼び出しが行われているかどうかが考慮されます。
「使用バイト」の範囲内で作成されます。 そうである場合、そのデータを構成する基礎となるバイトは、
UTF-8 文字列は、それが表す文字ではなく公開されます。 しかし、このプラグマは
実際には、デバッグと、場合によってはバイト レベルでの低レベルのテストにのみ使用する必要があります。
したがって、ほとんどの XS コードはこれに関係する必要はありませんが、Perl コアのさまざまな領域が考慮されます。
それをサポートする必要があります。
そして、これがすべてではありません。 Perl v5.12 以降、エンコードされていない文字列
UTF-8 は、さまざまな条件下で Unicode として扱われる場合もあります (「ASCII ルールと ASCII ルールの比較」を参照)
perlunicode の Unicode ルール」。これは実際に問題となるのは、
序数は 128 ~ 255 であり、その動作は ASCII と Unicode で異なります。
コードが考慮する方法でルールを修正します (perlunicode の「Unicode バグ」を参照)。 そこには
変更される可能性があるため、これに対処するための API は公開されていませんが、以下を参照してください。
「pp_lc」のコード pp.c 現在どのように行われているかの例を示します。
認定条件 do I 変換 a string 〜へ UTF-8?
UTF-8 文字列と非 UTF-8 文字列が混在している場合は、非 UTF-8 文字列をアップグレードする必要があります。
文字列を UTF-8 に変換します。 SV をお持ちの場合、これを行う最も簡単な方法は次のとおりです。
sv_utf8_upgrade(sv);
ただし、次のようなことは行わないでください。
if (!SvUTF8(左))
sv_utf8_upgrade(左);
これを二項演算子で行うと、実際には受け取った文字列の XNUMX つが変更されます。
エンドユーザーには気づかれないはずですが、オペレーターに影響を与える可能性があります。
欠陥のあるコードの問題。
代わりに、「bytes_to_utf8」を使用すると、UTF-8 でエンコードされたファイルが得られます。 copy 文字列引数の。 これ
を損なうことなく、データを比較などに利用できるようにするのに役立ちます。
オリジナルSV。 逆の方法として「utf8_to_bytes」もありますが、当然のことながら、これは
単一で表現できない 255 を超える文字が文字列に含まれている場合は失敗します。
バイト。
認定条件 do I 比較します 文字列?
perlapi の「sv_cmp」と perlapi の「sv_cmp_flags」は、XNUMX つの SV の辞書編集的な比較を行います。
UTF-8 を適切に処理します。 ただし、Unicode ではさらに複雑なコードが指定されていることに注意してください。
照合のメカニズム。Unicode::Collate モジュール経由で利用可能。
XNUMX つの文字列が等しいかどうかを比較するだけであれば、「memEQ()」と「memEQ()」を使用するだけです。
通常どおり「memNE()」。ただし、文字列は UTF-8 でエンコードされているか、UTF-8 でエンコードされていない必要があります。
8 つの文字列を大文字と小文字を区別せずに比較するには、「foldEQ_utfXNUMX()」を使用します (文字列を比較する必要はありません)
同じ UTF-8 性を持ちます)。
Is そこ 何でも ほかに I 必要 〜へ 知っている?
あまり。 以下のことを覚えておいてください。
· 「char *」または「U8 *」文字列が UTF-8 であるかどうかを判断する方法はありません。 でも君ならできる
SV を文字列化した後に「DO_UTF8」を呼び出して、SV を UTF-8 として扱うかどうかを指示します。
「SvPV」または同様のマクロを使用します。 そして、SV が実際に UTF-8 であるかどうかを知ることができます (たとえ
そのように扱われません)「SvUTF8」フラグを確認してください(再度後ほど)
文字列化します)。 UTF-8 にする必要がある場合は、フラグを設定することを忘れないでください。 扱う
旗をPVの一部として、そうではなくても、そのPVをどこかに渡したら、
旗も渡してください。
· 文字列が UTF-8 の場合、 常に そうでない限り、値を取得するには「utf8_to_uvchr_buf」を使用してください。
「UTF8_IS_INVARIANT(*s)」の場合、*s を使用できます。
・UTF-8文字列に文字UVを書き込む場合、 常に そうでない場合は、「uvchr_to_utf8」を使用してください。
"UVCHR_IS_INVARIANT(uv))" この場合、"*s = uv" を使用できます。
· UTF-8 文字列と非 UTF-8 文字列を混在させるのは難しいです。 「bytes_to_utf8」を使用して新しい文字列を取得します
これは UTF-8 でエンコードされており、それらを結合します。
カスタム オペレーター
カスタム オペレーターのサポートは、独自の操作を定義できるようにする実験的な機能です。
これは主に、Perl で他の言語のインタプリタを構築できるようにするためです。
コアですが、「マクロ操作」(マクロ操作) の作成による最適化も可能です。
「gvsv、
gvsv、追加します。)
この機能は、新しい op タイプ「OP_CUSTOM」として実装されます。 Perl コアは「認識」しません
この操作タイプには特別なものがないため、最適化には関与しません。
これは、カスタム演算を任意の演算構造 (単項、単項、単項など) として定義できることも意味します。
バイナリ、リストなど、お好みで。
カスタム演算子が何をしてくれないのかを知っておくことが重要です。 新しいものを追加することはできません
構文を Perl に直接変換します。 新しいキーワードを直接追加することさえできません。 実際には、
Perl がプログラムをコンパイルする方法はまったく変わりません。 それらの変更を行わなければなりません
Perl がプログラムをコンパイルした後、自分で実行してください。 これを行うには、op を操作します。
「CHECK」ブロックと「B::Generate」モジュールを使用するか、カスタムのぞき穴を追加してツリーを作成します。
「最適化」モジュールを使用したオプティマイザー。
これを行うときは、
「OP_CUSTOM」と独自の PP 関数の「op_ppaddr」を入力します。 これは次のように定義する必要があります
XS コードであり、「pp_*.c」の PP ops のように見えるはずです。 確保するのはあなた自身の責任です
操作がスタックから適切な数の値を取得し、
必要に応じてスタック マークを追加します。
また、op を Perl インタープリタに「登録」して、
意味のあるエラーおよび警告メッセージ。 複数のカスタム操作を使用できるため
XNUMX つの「論理」OP タイプ「OP_CUSTOM」内で、Perl は「o->op_ppaddr」の値を使用して、
どのカスタム op を扱っているかを判断します。 「XOP」構造を作成する必要があります。
使用する各 paddr は、「XopENTRY_set」でカスタム op のプロパティを設定し、登録します
「Perl_custom_op_register」を使用して、ppaddr に対する構造体を作成します。 些細な例としては、
のように見える:
静的 XOP my_xop;
静的OP *my_pp(pTHX);
ブート:
XopENTRY_set(&my_xop, xop_name, "myxop");
XopENTRY_set(&my_xop, xop_desc, "役に立たないカスタム op");
Perl_custom_op_register(aTHX_ my_pp, &my_xop);
構造体で使用可能なフィールドは次のとおりです。
xop_name
オペレーションの短い名前。 これは一部のエラー メッセージに含まれるほか、
B モジュールによって「$op->name」として返されるため、モジュールの出力に表示されます。
B::簡潔なように。
xop_desc
オペレーションの機能の簡単な説明。
xop_class
この操作が使用するさまざまな *OP 構造のうちのどれ。 これは「OA_*」のいずれかである必要があります。
からの定数 作戦、すなわち、
OA_BASEOP
OA_UNOP
OA_BINOP
OA_LOGOP
OA_LISTOP
OA_PMOP
OA_SVOP
OA_PADOP
OA_PVOP_OR_SVOP
これは「PVOP」のみとして解釈される必要があります。 「_OR_SVOP」は、
コア「PVOP」、「OP_TRANS」は、代わりに「SVOP」になる場合があります。
OA_LOOP
OA_COP
他の「OA_*」定数は使用しないでください。
xop_peep
このメンバーのタイプは「Perl_cpeep_t」で、「void (*Perl_cpeep_t)(aTHX_ OP」に展開されます)
*o, OP *oldop)"。これが設定されている場合、この関数は次のときに "Perl_rpeep" から呼び出されます。
このタイプの操作は、ピープホール オプティマイザーによって検出されます。 o 必要なOPです
最適化; 古い操作 最適化された前の OP です。その「op_next」は o.
「B::Generate」は、名前によるカスタム操作の作成を直接サポートします。
作者
1997 年 XNUMX 月まで、この文書はジェフ・オカモトによって管理されていました。[メール保護]>。 それは
現在は Perl 5 ポーターによって Perl 自体の一部として維持されています。[メール保護]>.
Dean Roehrich、Malcolm Beattie、Andreas Koenig からの多くの支援と提案により、
ポール・ハドソン、イリヤ・ザカレヴィッチ、ポール・マーキス、ニール・バウワーズ、マシュー・グリーン、ティム・バンス、
スパイダー・ボードマン、ウルリッヒ・ファイファー、スティーブン・マッカマント、グルサミー・サラシー。
onworks.net サービスを使用してオンラインで perlguts を使用する