InglesPransesEspanyol

OnWorks favicon

perlpacktut - Online sa Cloud

Patakbuhin ang perlpacktut sa OnWorks na libreng hosting provider sa Ubuntu Online, Fedora Online, Windows online emulator o MAC OS online emulator

Ito ang command na perlpacktut na maaaring patakbuhin sa OnWorks na libreng hosting provider gamit ang isa sa aming maramihang libreng online na workstation gaya ng Ubuntu Online, Fedora Online, Windows online emulator o MAC OS online emulator

PROGRAMA:

NAME


perlpacktut - tutorial sa "pack" at "unpack"

DESCRIPTION


Ang "pack" at "unpack" ay dalawang function para sa pagbabago ng data ayon sa isang tinukoy ng user
template, sa pagitan ng binabantayang paraan ng pag-iimbak ng Perl ng mga halaga at ilang mahusay na tinukoy na representasyon
tulad ng maaaring kailanganin sa kapaligiran ng isang Perl program. Unfortunately, silang dalawa din
sa mga pinaka-hindi nauunawaan at pinakamadalas na hindi napapansing mga function na ibinibigay ng Perl. Ito
tutorial ay demystify ang mga ito para sa iyo.

Ang Basic Prinsipyo


Karamihan sa mga programming language ay hindi nagtatago sa memorya kung saan naka-imbak ang mga variable. Sa C, para sa
halimbawa, maaari mong kunin ang address ng ilang variable, at sasabihin sa iyo ng operator na "sizeof".
kung gaano karaming mga byte ang inilalaan sa variable. Gamit ang address at ang laki, maaari mong
i-access ang storage sa nilalaman ng iyong puso.

Sa Perl, hindi mo lang ma-access ang memory nang random, ngunit ang istruktura at representasyon
Ang conversion na ibinigay ng "pack" at "unpack" ay isang mahusay na alternatibo. Ang "pack"
function na nagko-convert ng mga halaga sa isang byte sequence na naglalaman ng mga representasyon ayon sa a
ibinigay na detalye, ang tinatawag na "template" na argumento. Ang "unpack" ay ang kabaligtaran na proseso,
pagkuha ng ilang mga halaga mula sa mga nilalaman ng isang string ng mga byte. (Mag-ingat, gayunpaman, na
hindi lahat ng pinagsama-sama ay maaaring maayos na i-unpack - isang napaka-karaniwang karanasan bilang
malamang na kumpirmahin ng mga batikang manlalakbay.)

Bakit, maaari mong itanong, kailangan mo ba ng isang tipak ng memorya na naglalaman ng ilang mga halaga sa binary
representasyon? Ang isang magandang dahilan ay ang pag-access ng input at output sa ilang file, device, o a
koneksyon sa network, kung saan ang binary na representasyong ito ay pinilit sa iyo o sa kalooban
bigyan ka ng ilang benepisyo sa pagproseso. Ang isa pang dahilan ay ang pagpasa ng data sa ilang system call
na hindi magagamit bilang isang Perl function: "syscall" ay nangangailangan sa iyo na magbigay ng mga parameter
nakaimbak sa paraang nangyayari ito sa isang C program. Kahit na ang pagpoproseso ng teksto (tulad ng ipinapakita sa susunod
seksyon) ay maaaring pasimplehin sa matalinong paggamit ng dalawang function na ito.

Upang makita kung paano gumagana ang (un)packing, magsisimula kami sa isang simpleng template code kung saan ang conversion
ay nasa mababang gear: sa pagitan ng mga nilalaman ng isang byte sequence at isang string ng hexadecimal
mga digit. Gamitin natin ang "unpack", dahil malamang na ito ay magpapaalala sa iyo ng isang dump program, o ilan
desperado huling mensahe kapus-palad na mga programa ay nakasanayan na ihagis sa iyo bago sila mag-expire
sa ligaw na asul doon. Ipagpalagay na ang variable na $mem ay nagtataglay ng isang sequence ng mga byte na iyon
gusto naming siyasatin nang hindi inaakala ang anumang kahulugan nito, maaari kaming sumulat

my( $hex ) = unpack( 'H*', $mem );
i-print ang "$hex\n";

kung saan maaari naming makita ang isang bagay na tulad nito, sa bawat pares ng hex digit na tumutugma sa
isang byte:

41204d414e204120504c414e20412043414e414c2050414e414d41

Ano ang nasa tipak ng alaala na ito? Mga numero, character, o pinaghalong pareho? Ipagpalagay na
kami ay nasa isang computer kung saan ginagamit ang ASCII (o ilang katulad) na pag-encode: mga hexadecimal na halaga sa
ang hanay na 0x40 - 0x5A ay nagpapahiwatig ng malaking titik, at ang 0x20 ay nag-e-encode ng espasyo. Kaya tayo
ipagpalagay na ito ay isang piraso ng teksto, na nababasa ng ilan tulad ng isang tabloid; ngunit gagawin ng iba
kailangang humawak ng ASCII table at muling buhayin ang pakiramdam ng firstgrader. Wala rin pakialam
marami tungkol sa kung aling paraan upang basahin ito, tandaan namin na "i-unpack" gamit ang template code na "H"
kino-convert ang mga nilalaman ng isang pagkakasunud-sunod ng mga byte sa karaniwang hexadecimal notation.
Dahil ang "isang pagkakasunud-sunod ng" ay isang medyo malabong indikasyon ng dami, ang "H" ay tinukoy sa
mag-convert lamang ng isang hexadecimal digit maliban kung ito ay sinusundan ng isang repeat count. An
Ang asterisk para sa repeat count ay nangangahulugang gamitin ang anumang natitira.

Ang kabaligtaran na operasyon - pag-iimpake ng mga nilalaman ng byte mula sa isang string ng mga hexadecimal digit - ay
kasing dali lang isulat. Halimbawa:

my $s = pack( 'H2' x 10, 30..39 );
i-print ang "$s\n";

Dahil pinapakain namin ang isang listahan ng sampung 2-digit na hexadecimal string sa "pack", ang template ng pack
dapat maglaman ng sampung pack code. Kung ito ay pinapatakbo sa isang computer na may ASCII character coding,
ito ay magpi-print sa 0123456789.

Pag-iimpake teksto


Ipagpalagay natin na kailangan mong magbasa sa isang file ng data tulad nito:

Petsa |Paglalarawan | Kita|Gasta
01/24/2001 Zed's Camel Emporium 1147.99
01/28/2001 Pag-spray ng flea 24.99
01/29/2001 Sumakay ng kamelyo sa mga turista 235.00

Paano natin ito gagawin? Maaari mong isipin muna na gumamit ng "split"; gayunpaman, dahil ang "split" ay bumagsak
mga blangkong field, hindi mo malalaman kung ang isang tala ay kita o paggasta. Oops. Well,
maaari mong palaging gamitin ang "substr":

habang (<>) {
my $date = substr($_, 0, 11);
my $desc = substr($_, 12, 27);
my $income = substr($_, 40, 7);
my $expend = substr($_, 52, 7);
...
}

Hindi naman talaga barrel of laughs diba? Sa katunayan, ito ay mas masahol kaysa sa maaaring mukhang; ang
agila-eyed ay maaaring mapansin na ang unang field ay dapat lamang na 10 character ang lapad, at ang
ang error ay lumaganap mismo sa iba pang mga numero - na kinailangan naming bilangin gamit ang kamay.
Kaya ito ay madaling kapitan ng pagkakamali pati na rin ang horribly hindi palakaibigan.

O baka maaari tayong gumamit ng mga regular na expression:

habang (<>) {
my($date, $desc, $income, $expend) =
m|(\d\d/\d\d/\d{4}) (.{27}) (.{7})(.*)|;
...
}

Urgh. Well, medyo mas maganda, pero - well, gusto mo bang mapanatili iyon?

Uy, hindi ba dapat gawing madali ni Perl ang ganitong uri ng bagay? Well, ginagawa nito, kung gagamitin mo ang
tamang kasangkapan. Ang "pack" at "unpack" ay idinisenyo upang tulungan ka kapag nakikitungo sa fixed-
lapad ng data tulad ng nasa itaas. Tingnan natin ang isang solusyon na may "unpack":

habang (<>) {
my($date, $desc, $income, $expend) = unpack("A10xA27xA7A*", $_);
...
}

Iyon ay mukhang mas maganda; ngunit kailangan nating alisin ang kakaibang template na iyon. Kung saan ako hinila
na mula sa?

OK, tingnan natin muli ang ilan sa aming data; sa katunayan, isasama namin ang mga header, at a
handy ruler para masubaybayan natin kung nasaan tayo.

1 2 3 4 5
1234567890123456789012345678901234567890123456789012345678
Petsa |Paglalarawan | Kita|Gasta
01/28/2001 Pag-spray ng flea 24.99
01/29/2001 Sumakay ng kamelyo sa mga turista 235.00

Mula dito, makikita natin na ang column ng petsa ay umaabot mula column 1 hanggang column 10 - ten
malawak na mga character. Ang "pack"-ese para sa "character" ay "A", at sampu sa mga ito ay "A10". Kaya kung
gusto lang naming kunin ang mga petsa, maaari naming sabihin ito:

my($date) = unpack("A10", $_);

OK, ano ang susunod? Sa pagitan ng petsa at paglalarawan ay isang blangkong column; gusto naming laktawan
sa ibabaw niyan. Ang "x" na template ay nangangahulugang "laktawan pasulong", kaya gusto namin ang isa sa mga iyon. Susunod, mayroon kami
isa pang batch ng mga character, mula 12 hanggang 38. Iyon ay 27 higit pang mga character, kaya "A27". (Huwag
gawin ang fencepost error - mayroong 27 character sa pagitan ng 12 at 38, hindi 26. Bilangin sila!)

Ngayon laktawan namin ang isa pang character at kunin ang susunod na 7 character:

my($date,$description,$income) = unpack("A10xA27xA7", $_);

Ngayon ay dumating ang matalino bit. Mga linya sa ating ledger na income lang at hindi gastusin
maaaring magtapos sa column 46. Kaya naman, hindi namin gustong sabihin sa aming "unpack" pattern na kami kailangan sa
maghanap ng isa pang 12 character; sasabihin na lang natin na "kung may natitira pa, kunin mo na". Tulad mo
maaaring hulaan mula sa mga regular na expression, iyon ang ibig sabihin ng "*": "gamitin ang lahat
natitira".

· Maging babala, gayunpaman, na hindi tulad ng mga regular na expression, kung ang "unpack" na template ay hindi
tumugma sa papasok na data, si Perl ay sisigaw at mamamatay.

Samakatuwid, pinagsama ang lahat:

aking ($petsa, $deskripsyon, $kita, $gasta) =
i-unpack("A10xA27xA7xA*", $_);

Ngayon, iyon ang aming data na na-parse. Sa palagay ko, kung ano ang gusto nating gawin ngayon ay ang kabuuan ng ating kita
at paggasta, at magdagdag ng isa pang linya sa dulo ng aming ledger - sa parehong format -
sinasabi kung magkano ang dinala namin at kung magkano ang nagastos namin:

habang (<>) {
my ($date, $desc, $income, $expend) =
i-unpack("A10xA27xA7xA*", $_);
$tot_income += $income;
$tot_expend += $expend;
}

$tot_income = sprintf("%.2f", $tot_income); # Ipasok sila
$tot_expend = sprintf("%.2f", $tot_expend); # "pinansyal" na format

$date = POSIX::strftime("%m/%d/%Y", localtime);

# OK, tayo:

print pack("A10xA27xA7xA*", $date, "Mga Kabuuan",
$tot_income, $tot_expend);

Oh, hmm. Iyon ay hindi masyadong gumana. Tingnan natin kung ano ang nangyari:

01/24/2001 Zed's Camel Emporium 1147.99
01/28/2001 Pag-spray ng flea 24.99
01/29/2001 Sumakay ng kamelyo sa mga turista 1235.00
03/23/2001Mga Kabuuan 1235.001172.98

OK, ito ay simula, ngunit ano ang nangyari sa mga espasyo? Naglagay tayo ng "x", hindi ba? Hindi ba dapat
lumaktaw pasulong? Tingnan natin kung ano ang sinasabi ng "pack" sa perlfunc:

x Isang null byte.

Urgh. Kaya pala. Mayroong malaking pagkakaiba sa pagitan ng "a null byte", character zero, at "a
space", character 32. Naglagay si Perl ng isang bagay sa pagitan ng petsa at paglalarawan - ngunit
sa kasamaang palad, hindi namin ito makita!

Ang talagang kailangan nating gawin ay palawakin ang lapad ng mga patlang. Ang "A" na format ay naglalagay ng anuman
mga hindi umiiral na mga character na may mga puwang, upang magamit namin ang mga karagdagang puwang upang ihanay ang aming
mga patlang, tulad nito:

print pack("A11 A28 A8 A*", $date, "Mga Kabuuan",
$tot_income, $tot_expend);

(Tandaan na maaari kang maglagay ng mga puwang sa template upang gawin itong mas nababasa, ngunit hindi
isalin sa mga puwang sa output.) Narito ang nakuha namin sa oras na ito:

01/24/2001 Zed's Camel Emporium 1147.99
01/28/2001 Pag-spray ng flea 24.99
01/29/2001 Sumakay ng kamelyo sa mga turista 1235.00
03/23/2001 Mga Kabuuan 1235.00 1172.98

Iyan ay medyo mas mahusay, ngunit mayroon pa rin tayong huling column na kailangang ilipat pa
tapos na. Mayroong isang madaling paraan upang ayusin ito: sa kasamaang-palad, hindi namin makuha ang "pack" sa kanan-
bigyang-katwiran ang aming mga patlang, ngunit maaari naming makuha ang "sprintf" upang gawin ito:

$tot_income = sprintf("%.2f", $tot_income);
$tot_expend = sprintf("%12.2f", $tot_expend);
$date = POSIX::strftime("%m/%d/%Y", localtime);
print pack("A11 A28 A8 A*", $date, "Mga Kabuuan",
$tot_income, $tot_expend);

Sa pagkakataong ito makuha natin ang tamang sagot:

01/28/2001 Pag-spray ng flea 24.99
01/29/2001 Sumakay ng kamelyo sa mga turista 1235.00
03/23/2001 Mga Kabuuan 1235.00 1172.98

Kaya ganoon kami kumukonsumo at gumagawa ng fixed-width na data. Balikan natin ang nakita natin
"pack" at "unpack" sa ngayon:

· Gamitin ang "pack" upang pumunta mula sa ilang piraso ng data patungo sa isang fixed-width na bersyon; gamitin ang "unpack"
upang gawing ilang piraso ng data ang isang fixed-width-format na string.

· Ang format ng pack na "A" ay nangangahulugang "anumang karakter"; kung ikaw ay "nag-iimpake" at naubusan ka na
mga bagay na iimpake, pupunuin ng "pack" ang natitira ng mga puwang.

· Ang ibig sabihin ng "x" ay "laktawan ang isang byte" kapag "i-unpack"; kapag "nag-impake", ang ibig sabihin ay "introduce a null
byte" - malamang na hindi iyon ang ibig mong sabihin kung nakikipag-usap ka sa simpleng teksto.

· Maaari mong sundin ang mga format na may mga numero upang sabihin kung gaano karaming mga character ang dapat maapektuhan
sa pamamagitan ng format na iyon: "A12" ay nangangahulugang "kumuha ng 12 character"; Ang ibig sabihin ng "x6" ay "laktawan ang 6 byte" o
"character 0, 6 beses".

· Sa halip na isang numero, maaari mong gamitin ang "*" upang nangangahulugang "ubusin ang lahat ng natitira."

babala: kapag nag-iimpake ng maraming piraso ng data, ang "*" ay nangangahulugang "kunin ang lahat ng
kasalukuyang piraso ng data". Ibig sabihin

pack("A*A*", $isa, $dalawa)

i-pack ang lahat ng $isa sa unang "A*" at pagkatapos ang lahat ng $two sa pangalawa. Ito ay
pangkalahatang prinsipyo: ang bawat format na character ay tumutugma sa isang piraso ng data upang maging
"pack" ed.

Pag-iimpake Numero


Napakarami para sa data ng teksto. Magpatuloy tayo sa mga bagay na karne na "i-pack" at "i-unpack" ang pinakamainam
sa: paghawak ng mga binary na format para sa mga numero. Mayroong, siyempre, hindi lamang isang binary na format
- magiging napakasimple ng buhay - ngunit gagawin ni Perl ang lahat ng maselan na trabaho para sa iyo.

Integers
Ang pag-iimpake at pag-unpack ng mga numero ay nagpapahiwatig ng conversion sa at mula sa ilan tiyak doble
representasyon. Ang pag-iwan sa mga floating point na numero sa isang tabi para sa sandaling ito, ang kapansin-pansin
Ang mga katangian ng anumang naturang representasyon ay:

· ang bilang ng mga byte na ginamit para sa pag-iimbak ng integer,

· kung ang mga nilalaman ay binibigyang kahulugan bilang isang pinirmahan o hindi nalagdaan na numero,

· ang pag-order ng byte: kung ang unang byte ay ang pinakamaliit o pinakamahalagang byte (o:
little-endian o big-endian, ayon sa pagkakabanggit).

Kaya, halimbawa, upang i-pack ang 20302 sa isang nilagdaang 16 bit integer sa iyong computer
representasyong isinulat mo

my $ps = pack( 's', 20302 );

Muli, ang resulta ay isang string, na ngayon ay naglalaman ng 2 bytes. Kung ipi-print mo ang string na ito (na,
sa pangkalahatan, hindi inirerekomenda) maaari mong makita ang "ON" o "NO" (depende sa byte ng iyong system
pag-order) - o isang bagay na ganap na naiiba kung ang iyong computer ay hindi gumagamit ng ASCII na character
encoding. Ang pag-unpack ng $ps na may parehong template ay nagbabalik ng orihinal na halaga ng integer:

my( $s ) = unpack( 's', $ps );

Ito ay totoo para sa lahat ng numeric na template code. Ngunit huwag asahan ang mga himala: kung ang nakaimpake
lumampas ang halaga sa inilaang kapasidad ng byte, tahimik na itinatapon ang mga high order bit, at
Ang i-unpack ay tiyak na hindi magagawang hilahin ang mga ito pabalik sa ilang mahiwagang sumbrero. At, kapag nag-impake ka
gamit ang isang nilagdaang template code gaya ng "s", ang isang labis na halaga ay maaaring magresulta sa sign bit
pag-aayos, at ang pag-unpack nito ay matalinong magbabalik ng negatibong halaga.

Hindi ka masyadong malalayo ng 16 bits sa mga integer, ngunit mayroong "l" at "L" para sa nilagdaan at
unsigned 32-bit integers. At kung ito ay hindi sapat at ang iyong system ay sumusuporta sa 64 bit
integers maaari mong itulak ang mga limitasyon nang mas malapit sa infinity gamit ang mga pack code na "q" at "Q". A
Ang kapansin-pansing pagbubukod ay ibinibigay ng mga pack code na "i" at "I" para sa mga pinirmahan at hindi nalagdaan na mga integer
ng iba't-ibang "lokal na custom": Ang ganitong integer ay kukuha ng kasing dami ng byte gaya ng lokal na C
nagbabalik ang compiler para sa "sizeof(int)", ngunit gagamitin nito at pinakamaliit 32 na piraso.

Ang bawat isa sa mga integer pack code na "sSlLqQ" ay nagreresulta sa isang nakapirming bilang ng mga byte, kahit na
kung saan mo isinasagawa ang iyong programa. Ito ay maaaring maging kapaki-pakinabang para sa ilang mga application, ngunit ito ay hindi
magbigay ng isang portable na paraan upang maipasa ang mga istruktura ng data sa pagitan ng mga programang Perl at C (nakatali sa
nangyayari kapag tinawag mo ang mga extension ng XS o ang function ng Perl na "syscall"), o kapag nagbasa ka o
magsulat ng mga binary file. Ang kakailanganin mo sa kasong ito ay mga template code na nakadepende sa kung ano
ang iyong lokal na C compiler ay nag-compile kapag nag-code ka ng "maikli" o "hindi naka-sign na mahaba", halimbawa.
Ang mga code na ito at ang kanilang mga katumbas na haba ng byte ay ipinapakita sa talahanayan sa ibaba. Mula noong
Ang pamantayang C ay nag-iiwan ng malaking pahinga kaugnay ng mga kamag-anak na laki ng mga uri ng data na ito,
maaaring mag-iba ang aktwal na mga halaga, at iyon ang dahilan kung bakit ibinibigay ang mga halaga bilang mga expression sa C at Perl.
(Kung gusto mong gumamit ng mga halaga mula sa %Config sa iyong program kailangan mong i-import ito gamit ang "use
Config".)

nilagdaan ang unsigned byte na haba sa C byte na haba sa Perl
s! S! sizeof(short) $Config{shortsize}
ako! ako! sizeof(int) $Config{intsize}
l! L! sizeof(long) $Config{longsize}
q! Q! sizeof(long long) $Config{longlongsize}

Ang "ako!" at ako!" ang mga code ay hindi naiiba sa "i" at "I"; sila ay kinukunsinti para sa
kapakanan ng pagkakumpleto.

Hindi nakabalot a Magtalaksan Balangkas
Maaaring kailanganin ang paghiling ng partikular na pag-order ng byte kapag nagtatrabaho ka sa binary data
na nagmumula sa ilang partikular na arkitektura samantalang ang iyong programa ay maaaring tumakbo nang buo
magkaibang sistema. Bilang halimbawa, ipagpalagay na mayroon kang 24 na byte na naglalaman ng isang stack frame bilang ito
nangyayari sa isang Intel 8086:

+---------+ +----+----+ +---------+
TOS: | IP | TOS+4:| FL | FH | FLAGS TOS+14:| SI |
+---------+ +----+----+ +---------+
| CS | | AL | AH | AX | DI |
+---------+ +----+----+ +---------+
| BL | BH | BX | BP |
+----+----+ +---------+
| CL | CH | CX | DS |
+----+----+ +---------+
| DL | DH | DX | ES |
+----+----+ +---------+

Una, tandaan namin na ang 16-bit na CPU na ito na pinarangalan ng oras ay gumagamit ng little-endian order, at iyon ang dahilan kung bakit
ang low order byte ay nakaimbak sa ibabang address. Upang i-unpack ang tulad ng isang (unsigned) maikling gagawin namin
kailangang gumamit ng code na "v". Ang isang paulit-ulit na bilang ay naglalabas ng lahat ng 12 shorts:

my( $ip, $cs, $flags, $ax, $bx, $cd, $dx, $si, $di, $bp, $ds, $es ) =
i-unpack( 'v12', $frame );

Bilang kahalili, maaari sana naming gamitin ang "C" upang i-unpack ang mga indibidwal na naa-access na byte register
FL, FH, AL, AH, atbp.:

my( $fl, $fh, $al, $ah, $bl, $bh, $cl, $ch, $dl, $dh ) =
unpack( 'C10', substr( $frame, 4, 10 ) );

Magiging maganda kung magagawa natin ito sa isang iglap: i-unpack ang isang maikli, i-back up ng kaunti,
at pagkatapos ay i-unpack ang 2 byte. Mula kay Perl is maganda, nag-aalok ito ng template code na "X" upang i-back up
isang byte. Pagsasama-sama ng lahat ng ito, maaari na nating isulat:

my( $ip, $cs,
$flag,$fl,$fh,
$ax,$al,$ah, $bx,$bl,$bh, $cx,$cl,$ch, $dx,$dl,$dh,
$si, $di, $bp, $ds, $es ) =
i-unpack( 'v2' . ('vXXCC' x 5) . 'v5', $frame );

(Maaaring iwasan ang clumsy construction ng template - basahin mo lang!)

Nagsumikap kami sa paggawa ng template upang tumugma ito sa mga nilalaman ng aming
buffer ng frame. Kung hindi, makakakuha tayo ng mga hindi natukoy na halaga, o hindi ma-unpack ang "unpack".
lahat. Kung ang "pack" ay maubusan ng mga item, magbibigay ito ng mga null string (na pinipilit sa
mga zero sa tuwing sinasabi ng pack code).

Gaano sa Kumain an Itlog on a lambat
Ang pack code para sa big-endian (high order byte sa pinakamababang address) ay "n" para sa 16 bit at
"N" para sa 32 bit integer. Ginagamit mo ang mga code na ito kung alam mong nagmula ang iyong data sa a
sumusunod na arkitektura, ngunit, sapat na nakakagulat, dapat mo ring gamitin ang mga pack code na ito kung
nagpapalitan ka ng binary data, sa buong network, na may ilang sistema na alam mo sa tabi
wala tungkol sa. Ang simpleng dahilan ay ang order na ito ay napili bilang ang network order,
at lahat ng mga programang may takot sa pamantayan ay dapat sumunod sa kumbensyong ito. (Ito ay, siyempre, a
mahigpit na suporta para sa isa sa mga Lilliputian na partido at maaaring makaimpluwensya sa pulitika
pag-unlad doon.) Kaya, kung inaasahan ng protocol na magpadala ka ng mensahe sa pamamagitan ng pagpapadala ng
haba muna, na sinusundan ng napakaraming byte, maaari mong isulat:

my $buf = pack( 'N', length( $msg ) ) . $msg;

o kahit na:

my $buf = pack( 'NA*', length( $msg ), $msg );

at ipasa ang $buf sa iyong gawain sa pagpapadala. Hinihiling ng ilang protocol na dapat isama ang bilang
ang haba ng bilang mismo: pagkatapos ay magdagdag lamang ng 4 sa haba ng data. (Pero siguraduhing basahin
"Lengths and Widths" bago mo talaga ito i-code!)

Byte-order nagbabago
Sa mga nakaraang seksyon natutunan namin kung paano gamitin ang "n", "N", "v" at "V" upang mag-pack at mag-unpack
mga integer na may big- o little-endian byte-order. Habang ito ay maganda, ito pa rin sa halip
limitado dahil iniiwan nito ang lahat ng uri ng mga naka-sign na integer pati na rin ang mga 64-bit na integer. Para sa
halimbawa, kung gusto mong i-unpack ang isang sequence ng mga sign na big-endian na 16-bit integer sa isang
platform-independent na paraan, kailangan mong isulat ang:

my @data = unpack 's*', pack 'S*', unpack 'n*', $buf;

Pangit ito. Mula sa Perl 5.9.2, mayroong isang mas magandang paraan upang ipahayag ang iyong pagnanais para sa isang
ilang byte-order: ang ">" at "<" modifiers. Ang ">" ay ang big-endian modifier, habang ang "<"
ay ang little-endian modifier. Gamit ang mga ito, maaari naming muling isulat ang code sa itaas bilang:

my @data = unpack 's>*', $buf;

Tulad ng nakikita mo, ang "malaking dulo" ng arrow ay humahawak sa "s", na isang magandang paraan upang
tandaan na ang ">" ay ang big-endian modifier. Ang parehong malinaw na gumagana para sa "<", kung saan ang
"maliit na dulo" pindutin ang code.

Malamang na mas kapaki-pakinabang ang mga modifier na ito kung kailangan mong harapin ang malaki- o
little-endian C na mga istruktura. Tiyaking basahin ang "Pag-iimpake at Pag-unpack ng Mga Structure ng C" para sa higit pa
sa na.

Lumulutang punto Numero
Para sa pagpapakete ng mga floating point na numero mayroon kang pagpipilian sa pagitan ng mga pack code na "f", "d",
"F" at "D". "f" at "d" pack sa (o i-unpack mula sa) single-precision o double-precision
representasyon bilang ito ay ibinigay ng iyong system. Kung sinusuportahan ito ng iyong mga system, maaaring ang "D".
ginagamit upang mag-pack at mag-unpack ng ("mahabang doble") na mga halaga, na maaaring mag-alok ng higit pang resolusyon kaysa
"f" o "d". nota na doon ay iba mahaba double format.

Ang "F" ay naglalaman ng isang "NV", na siyang uri ng floating point na ginagamit ng Perl sa loob.

Walang ganoong bagay bilang isang representasyon ng network para sa reals, kaya kung gusto mong ipadala ang iyong
totoong mga numero sa mga hangganan ng computer, mas mabuting manatili ka sa representasyon ng teksto,
posibleng gamit ang hexadecimal float na format (pag-iwas sa pagkawala ng conversion ng decimal), maliban kung
talagang sigurado ka kung ano ang nasa kabilang dulo ng linya. Para sa higit pa
adventuresome, maaari mong gamitin ang byte-order modifier mula sa nakaraang seksyon din sa
mga floating point code.

Galing sa ibang bansa Template


kaunti String
Ang mga bit ay ang mga atomo sa mundo ng memorya. Maaaring kailangang gumamit ng access sa mga indibidwal na bit
alinman bilang isang huling paraan o dahil ito ang pinaka maginhawang paraan upang pangasiwaan ang iyong data. bit
string (un)packing ay nagko-convert sa pagitan ng mga string na naglalaman ng serye ng 0 at 1 character at
isang pagkakasunud-sunod ng mga byte bawat isa ay naglalaman ng isang pangkat ng 8 bits. Ito ay halos kasing simple nito
mga tunog, maliban na may dalawang paraan na maaaring maisulat ang mga nilalaman ng isang byte bilang kaunti
string. Tingnan natin ang isang annotated byte:

7 6 5 4 3 2 1 0
+-----------------+
| 1 0 0 0 1 1 0 0 |
+-----------------+
MSB LSB

Paulit-ulit itong kumakain ng itlog: Iniisip ng ilan na dapat itong isulat
"10001100" ibig sabihin, simula sa pinaka makabuluhang bit, iginigiit ng iba ang "00110001".
Well, si Perl ay hindi bias, kaya't mayroon kaming dalawang bit string code:

$byte = pack( 'B8', '10001100' ); # magsimula sa MSB
$byte = pack( 'b8', '00110001' ); # magsimula sa LSB

Hindi posibleng mag-pack o mag-unpack ng mga bit field - mga integral byte lang. "pack" palagi
magsisimula sa susunod na hangganan ng byte at "nag-iikot" sa susunod na multiple ng 8 sa pamamagitan ng pagdaragdag ng zero
bits kung kinakailangan. (Kung gusto mo ng mga bit field, mayroong "vec" sa perlfunc. O kaya mo
ipatupad ang bit field handling sa antas ng string ng character, gamit ang split, substr, at
pagsasama-sama sa mga naka-unpack na bit string.)

Upang ilarawan ang pag-unpack para sa mga bit string, magdedecompose kami ng isang simpleng status register (isang "-"
ay kumakatawan sa isang "nakareserba" na bit):

+-----------------+------------------+
| SZ - A - P - C | - - - - ODIT |
+-----------------+------------------+
MSB LSB MSB LSB

Ang pag-convert ng dalawang byte na ito sa isang string ay maaaring gawin gamit ang unpack template na 'b16'. Upang
makuha ang indibidwal na bit value mula sa bit string na ginagamit namin "split" na may "empty"
pattern ng separator na naghihiwalay sa mga indibidwal na character. Mga halaga ng bit mula sa
Ang mga "nakareserba" na posisyon ay itinalaga lamang sa "undef", isang maginhawang notasyon para sa "I don't
bahala kung saan ito pupunta."

($carry, undef, $parity, undef, $auxcarry, undef, $zero, $sign,
$trace, $interrupt, $direction, $overflow) =
split( //, unpack( 'b16', $status ) );

Maaari rin kaming gumamit ng template na i-unpack na 'b12', dahil ang huling 4 na bit ay maaaring
hindi pinansin pa rin.

Uuencoding
Ang isa pang odd-man-out sa template alphabet ay ang "u", na may kasamang "uuecoded string".
(Ang "uu" ay maikli para sa Unix-to-Unix.) Malamang na hindi mo na kakailanganin ang encoding na ito.
pamamaraan na naimbento upang malampasan ang mga pagkukulang ng makalumang transmission
mga medium na hindi sumusuporta maliban sa simpleng ASCII data. Ang mahahalagang recipe ay simple:
Kumuha ng tatlong byte, o 24 bits. Hatiin ang mga ito sa 4 na anim na pakete, magdagdag ng espasyo (0x20) sa bawat isa.
Ulitin hanggang ang lahat ng data ay pinaghalo. I-fold ang mga pangkat ng 4 na byte sa mga linyang hindi hihigit sa
60 at palamutihan ang mga ito sa harap ng orihinal na bilang ng byte (incremented ng 0x20) at isang "\n"
sa dulo. - Ihahanda ito ng chef ng "pack" para sa iyo, ilang minuto, kapag pinili mo ang pack
code "u" sa menu:

my $uubuf = pack( 'u', $bindat );

Ang isang umuulit na bilang pagkatapos ng "u" ay nagtatakda ng bilang ng mga byte na ilalagay sa isang uuencoded na linya, na
ang maximum na 45 bilang default, ngunit maaaring itakda sa ilang (mas maliit) integer multiple ng
tatlo. Binabalewala lang ng "unpack" ang repeat count.

paggawa Mga kabuuan
Ang isang hindi kilalang template code ay "%"numero>. Una, dahil ginagamit ito bilang prefix sa
ilang iba pang template code. Pangalawa, dahil hindi ito magagamit sa "pack" sa lahat, at pangatlo,
sa "unpack", hindi ibinabalik ang data gaya ng tinukoy ng template code na nauuna nito. sa halip
bibigyan ka nito ng integer ng numero mga bit na nakalkula mula sa halaga ng data sa pamamagitan ng paggawa
kabuuan. Para sa mga numerong unpack code, walang malaking tagumpay ang natamo:

my $buf = pack( 'iii', 100, 20, 3 );
print unpack( '%32i3', $buf ), "\n"; # print 123

Para sa mga halaga ng string, ibinabalik ng "%" ang kabuuan ng mga halaga ng byte na nagse-save sa iyo ng problema ng isang kabuuan
loop na may "substr" at "ord":

print unpack( '%32A*', "\x01\x10" ), "\n"; # mga kopya 17

Bagama't nakadokumento ang "%" code bilang nagbabalik ng "checksum": huwag ilagay ang iyong tiwala
ganyang values! Kahit na inilapat sa isang maliit na bilang ng mga byte, hindi sila magagarantiya ng a
kapansin-pansing distansya ng Hamming.

Kaugnay ng "b" o "B", ang "%" ay nagdaragdag lamang ng mga piraso, at ito ay magagamit nang mabuti sa
bilangin ang mga set bit nang mahusay:

my $bitcount = unpack( '%32b*', $mask );

At ang pantay na parity bit ay maaaring matukoy tulad nito:

my $evenparity = unpack( '%1b*', $mask );

Unicode
Ang Unicode ay isang set ng character na maaaring kumatawan sa karamihan ng mga character sa karamihan ng mundo
mga wika, na nagbibigay ng puwang para sa higit sa isang milyong iba't ibang mga character. Tinutukoy ng Unicode 3.1
94,140 character: Ang Basic Latin character ay itinalaga sa mga numerong 0 - 127. Ang
Latin-1 Supplement na may mga character na ginagamit sa ilang mga European na wika ay nasa
susunod na hanay, hanggang 255. Pagkatapos ng ilan pang Latin na extension ay makikita natin ang mga set ng character mula sa
mga wikang gumagamit ng mga alpabetong hindi Romano, na sinasalihan ng iba't ibang set ng simbolo tulad ng
mga simbolo ng pera, Zapf Dingbats o Braille. (Baka gusto mong bumisita
<http://www.unicode.org/> para sa isang pagtingin sa ilan sa kanila - ang aking mga personal na paborito ay Telugu
at Kannada.)

Ang Unicode character set ay nag-uugnay ng mga character sa mga integer. Pag-encode ng mga numerong ito sa
ang pantay na bilang ng mga byte ay hihigit sa doble ng mga kinakailangan para sa pag-iimbak ng mga tekstong nakasulat
sa mga alpabetong Latin. Iniiwasan ito ng pag-encode ng UTF-8 sa pamamagitan ng pag-iimbak ng pinakakaraniwan (mula sa a
western point of view) mga character sa isang solong byte habang ini-encode ang mga mas bihira sa tatlo
o higit pang mga byte.

Gumagamit ang Perl ng UTF-8, sa loob, para sa karamihan ng mga string ng Unicode.

Kaya ano ang kinalaman nito sa "pack"? Well, kung gusto mong bumuo ng Unicode string
(na panloob na naka-encode bilang UTF-8), magagawa mo ito sa pamamagitan ng paggamit ng template code na "U". Bilang isang
halimbawa, gawin natin ang simbolo ng Euro currency (code number 0x20AC):

$UTF8{Euro} = pack( 'U', 0x20AC );
# Katumbas ng: $UTF8{Euro} = "\x{20ac}";

Ang pag-inspeksyon sa $UTF8{Euro} ay nagpapakita na naglalaman ito ng 3 byte: "\xe2\x82\xac". Gayunpaman, ito
naglalaman lamang ng 1 character, numero 0x20AC. Maaaring kumpletuhin ang round trip gamit ang "unpack":

$Unicode{Euro} = unpack( 'U', $UTF8{Euro} );

Ang pag-unpack gamit ang "U" na template code ay gumagana din sa UTF-8 na naka-encode na mga byte string.

Karaniwang gugustuhin mong mag-pack o mag-unpack ng mga string ng UTF-8:

# pack at i-unpack ang Hebrew alphabet
my $alefbet = pack( 'U*', 0x05d0..0x05ea );
my @hebrew = unpack( 'U*', $utf );

Pakitandaan: sa pangkalahatang kaso, mas mahusay kang gumamit ng Encode::decode_utf8 para mag-decode ng
Na-encode ng UTF-8 ang byte string sa isang Perl Unicode string, at Encode::encode_utf8 para mag-encode ng
Perl Unicode string sa UTF-8 bytes. Ang mga function na ito ay nagbibigay ng paraan ng paghawak ng di-wastong byte
mga pagkakasunud-sunod at sa pangkalahatan ay may mas magiliw na interface.

Isa pa portable binary Pag-encode
Ang pack code na "w" ay idinagdag upang suportahan ang isang portable binary data encoding scheme na iyon
lumalampas sa simpleng integer. (Makikita ang mga detalye sahttp://Casbah.org/>, ang Scarab
proyekto.) Isang BER (Binary Encoded Representation) ang naka-compress na unsigned integer stores base
128 na mga digit, pinakamahalagang digit muna, na may kaunting mga numero hangga't maaari. Bit eight (ang
high bit) ay nakatakda sa bawat byte maliban sa huli. Walang limitasyon sa laki sa pag-encode ng BER, ngunit
Ang Perl ay hindi magpapakalabis.

my $berbuf = pack( 'w*', 1, 128, 128+1, 128*128+127 );

Ang isang hex dump ng $berbuf, na may mga puwang na inilagay sa mga tamang lugar, ay nagpapakita ng 01 8100 8101
81807F. Dahil palaging mas mababa sa 128 ang huling byte, alam ng "unpack" kung saan titigil.

Template Pagpapangkat


Bago ang Perl 5.8, ang mga pag-uulit ng mga template ay kailangang gawin sa pamamagitan ng "x" -multiplication ng
mga string ng template. Ngayon ay may mas mahusay na paraan dahil maaari nating gamitin ang mga pack code na "(" at ")"
pinagsama sa isang paulit-ulit na bilang. Ang template na "i-unpack" mula sa halimbawa ng Stack Frame ay maaari
isulat lang na ganito:

i-unpack( 'v2 (vXXCC)5 v5', $frame )

I-explore natin ang feature na ito nang kaunti pa. Magsisimula tayo sa katumbas ng

sumali( '', mapa( substr( $_, 0, 1 ), @str ) )

na nagbabalik ng string na binubuo ng unang character mula sa bawat string. Gamit ang pack, kami
maaaring sumulat

pack( '(A)'.@str, @str )

o, dahil ang umuulit na bilang na "*" ay nangangahulugang "ulitin nang madalas hangga't kinakailangan", simple lang

pack( '(A)*', @str )

(Tandaan na ang template na "A*" ay naka-pack lamang ng $str[0] sa buong haba.)

Upang mag-pack ng mga petsa na nakaimbak bilang triplets ( araw, buwan, taon ) sa isang array @dates sa isang sequence
ng byte, byte, short integer na maaari nating isulat

$pd = pack( '(CCS)*', mapa( @$_, @dates ) );

Upang magpalit ng mga pares ng mga character sa isang string (na may pantay na haba) maaaring gumamit ng ilan
mga pamamaraan. Una, gamitin natin ang "x" at "X" upang lumaktaw pasulong at pabalik:

$s = pack( '(A)*', unpack( '(xAXXAx)*', $s ) );

Maaari rin nating gamitin ang "@" upang tumalon sa isang offset, na ang 0 ay ang posisyon kung saan tayo noong ang
huling "(" ay nakatagpo:

$s = pack( '(A)*', unpack( '(@1A @0A @2)*', $s ) );

Sa wakas, mayroon ding ganap na kakaibang diskarte sa pamamagitan ng pag-unpack ng malalaking endian shorts at
pag-iimpake ng mga ito sa reverse byte order:

$s = pack( '(v)*', unpack( '(n)*', $s );

Mga haba at Mga lapad


Pisi Mga haba
Sa nakaraang seksyon nakita namin ang isang mensahe sa network na binuo sa pamamagitan ng prefixing ng
binary na haba ng mensahe sa aktwal na mensahe. Makikita mo na ang pag-iimpake ng haba na sinusundan ng
napakaraming byte ng data ay isang madalas na ginagamit na recipe dahil hindi gagana ang pagdaragdag ng null byte
kung ang isang null byte ay maaaring bahagi ng data. Narito ang isang halimbawa kung saan ginagamit ang parehong mga diskarte:
pagkatapos ng dalawang null na winakasan na mga string na may pinagmulan at patutunguhang address, isang Maikling Mensahe (sa
isang mobile phone) ay ipinadala pagkatapos ng isang haba ng byte:

my $msg = pack( 'Z*Z*CA*', $src, $dst, length( $sm ), $sm );

Ang pag-unpack ng mensaheng ito ay maaaring gawin gamit ang parehong template:

($src, $dst, $len, $sm ) = unpack( 'Z*Z*CA*', $msg );

Mayroong isang banayad na bitag na nakakubli sa simula: Pagdaragdag ng isa pang field pagkatapos ng Maikling Mensahe
(sa variable na $sm) ay tama kapag nag-iimpake, ngunit hindi ito maaaring i-unpack nang walang muwang:

# mag-pack ng mensahe
my $msg = pack( 'Z*Z*CA*C', $src, $dst, length( $sm ), $sm, $prio );

# nabigo ang pag-unpack - nananatiling hindi natukoy ang $prio!
($src, $dst, $len, $sm, $prio ) = unpack( 'Z*Z*CA*C', $msg );

Ang pack code na "A*" ay lumalamon sa lahat ng natitirang byte, at ang $prio ay nananatiling hindi natukoy! Bago tayo
hayaang mapahina ng pagkabigo ang moral: Nakuha ni Perl ang trump card para gawin din ang trick na ito,
medyo malayo pa sa manggas. Panoorin ito:

# mag-pack ng mensahe: ASCIIZ, ASCIIZ, haba/string, byte
my $msg = pack( 'Z* Z* C/A* C', $src, $dst, $sm, $prio );

# i-unpack
($src, $dst, $sm, $prio ) = unpack( 'Z* Z* C/A* C', $msg );

Ang pagsasama-sama ng dalawang pack code na may slash ("/") ay iniuugnay ang mga ito sa isang solong halaga mula sa
listahan ng argumento. Sa "pack", ang haba ng argumento ay kinuha at naka-pack ayon sa
unang code habang ang argument mismo ay idinagdag pagkatapos ma-convert gamit ang template code
pagkatapos ng slash. Ito ay nagliligtas sa amin ng problema sa pagpasok ng "haba" na tawag, ngunit ito ay nasa
"i-unpack" kung saan talaga kami nakakapuntos: Ang halaga ng haba ng byte ay nagmamarka sa dulo ng string
na kukunin mula sa buffer. Dahil ang kumbinasyong ito ay walang kahulugan maliban kung ang
ang pangalawang pack code ay hindi "a*", "A*" o "Z*", hindi ka papayagan ni Perl.

Ang code ng pack na sinusundan ng "/" ay maaaring anumang bagay na akma upang kumatawan sa isang numero: Lahat ng
numeric binary pack code, at maging ang mga text code gaya ng "A4" o "Z*":

# pack/unpack ang isang string na sinusundan ng haba nito sa ASCII
my $buf = pack( 'A4/A*', "Humpty-Dumpty" );
# unpack $buf: '13 Humpty-Dumpty'
my $txt = unpack( 'A4/A*', $buf );

Ang "/" ay hindi ipinatupad sa Perls bago ang 5.6, kaya kung ang iyong code ay kinakailangan upang gumana sa mas luma
Perls kakailanganin mong "i-unpack( 'Z* Z* C')" para makuha ang haba, pagkatapos ay gamitin ito para gumawa ng bago
i-unpack ang string. Halimbawa

# mag-pack ng mensahe: ASCIIZ, ASCIIZ, haba, string, byte
# (5.005 compatible)
my $msg = pack( 'Z* Z* CA* C', $src, $dst, haba $sm, $sm, $prio );

# i-unpack
( undef, undef, $len) = unpack( 'Z* Z* C', $msg );
($src, $dst, $sm, $prio) = unpack ( "Z* Z* x A$len C", $msg );

Ngunit ang pangalawang "unpack" ay nagmamadali. Hindi ito gumagamit ng simpleng literal na string para sa
template. Kaya siguro kailangan nating magpakilala...

Dynamic Template
Sa ngayon, nakita namin ang mga literal na ginamit bilang mga template. Kung ang listahan ng mga item sa pakete ay wala
nakapirming haba, isang expression na bumubuo ng template ay kinakailangan (kahit kailan, para sa ilan
dahilan, "()*" ay hindi maaaring gamitin). Narito ang isang halimbawa: Upang mag-imbak ng pinangalanang mga halaga ng string sa isang paraan
na maginhawang ma-parse ng isang C program, lumikha kami ng pagkakasunod-sunod ng mga pangalan at null
winakasan ang mga string ng ASCII, na may "=" sa pagitan ng pangalan at halaga, na sinusundan ng isang
karagdagang delimiting null byte. Ganito:

my $env = pack( '(A*A*Z*)' . keys( %Env ) . 'C',
mapa( { ($_, '=', $Env{$_} ) } keys( %Env ) ), 0 );

Suriin natin ang mga cogs ng byte mill na ito, isa-isa. Nariyan ang "mapa" na tawag, na lumilikha ng
mga item na nilalayon naming ilagay sa $env buffer: sa bawat key (sa $_) idinaragdag nito ang "="
separator at ang halaga ng hash entry. Ang bawat triplet ay puno ng template code
sequence "A*A*Z*" na inuulit ayon sa bilang ng mga key. (Oo, iyon ang
Nagbabalik ang function na "keys" sa kontekstong scalar.) Upang makuha ang pinakahuling null byte, nagdaragdag kami ng 0 sa
ang dulo ng listahan ng "pack", na lagyan ng "C". (Maaaring napansin ng mga maasikasong mambabasa
na maaari naming tanggalin ang 0.)

Para sa reverse operation, kakailanganin nating tukuyin ang bilang ng mga item sa buffer
bago natin hayaang "i-unpack" itong hiwa-hiwalayin:

aking $n = $env =~ tr/\0// - 1;
my %env = mapa( split( /=/, $_ ), unpack( "(Z*)$n", $env ) );

Binibilang ng "tr" ang mga null byte. Ang "unpack" na tawag ay nagbabalik ng isang listahan ng mga pares ng pangalan-halaga bawat isa
na kung saan ay pinaghiwalay sa bloke ng "mapa".

Kailanan repetitions
Sa halip na mag-imbak ng sentinel sa dulo ng isang data item (o isang listahan ng mga item), magagawa namin
unahan ang datos na may bilang. Muli, nag-iimpake kami ng mga susi at halaga ng isang hash, bago ang bawat isa
na may hindi napirmahang bilang ng maikling haba, at sa unahan ay iniimbak namin ang bilang ng mga pares:

my $env = pack( 'S(S/A* S/A*)*', scalar keys( %Env ), %Env );

Pinapasimple nito ang reverse operation dahil ang bilang ng mga pag-uulit ay maaaring i-unpack
ang "/" code:

my %env = unpack( 'S/(S/A* S/A*)', $env );

Tandaan na isa ito sa mga bihirang kaso kung saan hindi mo magagamit ang parehong template para sa "pack"
at "i-unpack" dahil hindi matutukoy ng "pack" ang isang repeat count para sa isang "()"-group.

Intel HEX
Ang Intel HEX ay isang format ng file para sa kumakatawan sa binary data, karamihan ay para sa iba't ibang programming
chips, bilang isang text file. (Tingnanhttp://en.wikipedia.org/wiki/.hex> para sa isang detalyadong
paglalarawan, athttp://en.wikipedia.org/wiki/SREC_(file_format)> para sa Motorola
S-record na format, na maaaring i-unravel gamit ang parehong pamamaraan.) Bawat linya ay nagsisimula sa
isang tutuldok (':') at sinusundan ng isang pagkakasunod-sunod ng mga hexadecimal na character, na tumutukoy sa isang byte
bilangin n (8 bit), isang address (16 bit, big endian), isang uri ng record (8 bit), n data byte at
isang checksum (8 bit) na kinalkula bilang ang pinakamaliit na makabuluhang byte ng complement sum ng dalawa
ang mga naunang byte. Halimbawa: ":0300300002337A1E".

Ang unang hakbang ng pagproseso ng naturang linya ay ang conversion, sa binary, ng hexadecimal
data, para makuha ang apat na field, habang sinusuri ang checksum. Walang sorpresa dito: gagawin natin
magsimula sa isang simpleng "pack" na tawag upang i-convert ang lahat sa binary:

my $binrec = pack( 'H*', substr( $hexrec, 1 ) );

Ang resultang byte sequence ay pinaka-maginhawa para sa pagsuri sa checksum. Huwag pabagalin ang iyong
program down na may isang for loop na nagdaragdag ng mga "ord" na halaga ng mga byte ng string na ito - ang "unpack"
Ang code na "%" ay ang bagay na gagamitin para sa pag-compute ng 8-bit na kabuuan ng lahat ng byte, na dapat ay katumbas
sa zero:

mamatay maliban kung i-unpack( "%8C*", $binrec ) == 0;

Sa wakas, makuha natin ang apat na field na iyon. Sa ngayon, hindi ka dapat magkaroon ng anumang mga problema sa
unang tatlong field - ngunit paano natin magagamit ang byte count ng data sa unang field bilang a
haba para sa field ng data? Narito ang mga code na "x" at "X" ay dumating upang iligtas, ayon sa pinapayagan nila
paglukso pabalik-balik sa string upang i-unpack.

my( $addr, $type, $data ) = unpack( "xn C X4 C x3 /a", $bin );

Lumalaktaw ang code na "x" ng isang byte, dahil hindi pa namin kailangan ang bilang. Ang code "n" ay nangangalaga sa
16-bit na big-endian integer na address, at i-unpack ng "C" ang uri ng record. Nasa offset 4,
kung saan nagsisimula ang data, kailangan natin ang bilang. Ibinabalik tayo ng "X4" sa square one, which is the
byte sa offset 0. Ngayon ay kukunin natin ang bilang, at mag-zoom forth para ma-offset ang 4, kung nasaan tayo ngayon
kumpleto sa gamit upang kunin ang eksaktong bilang ng mga byte ng data, na iniiwan ang sumusunod na checksum
byte mag-isa.

Pag-iimpake at Hindi nakabalot C Kaayusan


Sa nakaraang mga seksyon nakita namin kung paano mag-pack ng mga numero at mga string ng character. Kung iyan ay
hindi para sa ilang mga snags maaari naming tapusin ang seksyong ito kaagad sa maikling pangungusap
na ang mga istruktura ng C ay hindi naglalaman ng anupaman, at samakatuwid ay alam mo na ang lahat
dito. Paumanhin, hindi: basahin mo, mangyaring.

Kung kailangan mong harapin ang maraming istrukturang C, at ayaw mong i-hack ang lahat ng iyong template
mano-mano ang mga string, malamang na gusto mong tingnan ang module ng CPAN
"Convert::Binary::C". Hindi lamang nito mai-parse nang direkta ang iyong C source, ngunit mayroon din itong built-
bilang suporta para sa lahat ng mga posibilidad at pagtatapos na inilarawan pa sa seksyong ito.

Ang Pagkakahanay Hukay
Sa pagsasaalang-alang ng bilis laban sa mga kinakailangan sa memorya, ang balanse ay nakatagilid
pabor sa mas mabilis na pagpapatupad. Naimpluwensyahan nito ang paraan ng paglalaan ng memorya ng mga C compiler
mga istruktura: Sa mga arkitektura kung saan ang isang 16-bit o 32-bit na operand ay maaaring ilipat nang mas mabilis sa pagitan
mga lugar sa memorya, o sa o mula sa isang rehistro ng CPU, kung ito ay nakahanay sa isang pantay o maramihang-
ng-apat o kahit na sa maramihang-ng walong address, isang C compiler ang magbibigay sa iyo ng ganitong bilis
makinabang sa pamamagitan ng pagpupuno ng mga dagdag na byte sa mga istruktura. Kung hindi mo tatawid sa C shoreline ito
ay hindi malamang na magdulot sa iyo ng anumang kalungkutan (bagama't dapat kang mag-ingat kapag nagdidisenyo ka ng malaking data
mga istruktura, o gusto mong maging portable ang iyong code sa pagitan ng mga arkitektura (gusto mo iyon,
hindi ba?)).

Upang makita kung paano ito nakakaapekto sa "pack" at "unpack", ihahambing namin ang dalawang istrukturang C na ito:

typedef struct {
char c1;
maikling s;
char c2;
mahaba l;
} gappy_t;

typedef struct {
mahaba l;
maikling s;
char c1;
char c2;
} siksik_t;

Karaniwan, ang isang C compiler ay naglalaan ng 12 bytes sa isang "gappy_t" na variable, ngunit nangangailangan lamang ng 8
bytes para sa isang "dense_t". Pagkatapos imbestigahan ito nang higit pa, maaari tayong gumuhit ng mga mapa ng memorya, na nagpapakita
kung saan nakatago ang dagdag na 4 na byte:

0 +4 +8 +12
+--+--+--+--+--+--+--+--+--+--+--+--+
|c1|xx| s |c2|xx|xx|xx| l | xx = punan ang byte
+--+--+--+--+--+--+--+--+--+--+--+--+
gappy_t

0 +4 +8
+--+--+--+--+--+--+--+--+
| l | h |c1|c2|
+--+--+--+--+--+--+--+--+
siksik_t

At doon ang unang quirk strike: "pack" at "unpack" na mga template ay kailangang palaman
na may mga "x" na code upang makuha ang mga karagdagang fill byte na iyon.

Ang natural na tanong: "Bakit hindi mabayaran ni Perl ang mga puwang?" ginagarantiyahan ang isang sagot. Isa
magandang dahilan ay ang mga C compiler ay maaaring magbigay ng (hindi ANSI) na mga extension na nagpapahintulot sa lahat ng uri
ng magarbong kontrol sa paraan ng pagkakahanay ng mga istruktura, kahit na sa antas ng isang indibidwal
larangan ng istraktura. At, kung ito ay hindi sapat, mayroong isang mapanlinlang na bagay na tinatawag na "unyon"
kung saan ang halaga ng mga fill byte ay hindi maaaring makuha mula sa pagkakahanay ng susunod na item
nag-iisa.

OK, kaya kumagat tayo sa bala. Narito ang isang paraan upang gawing tama ang pagkakahanay sa pamamagitan ng pagpasok
template codes "x", na hindi kumukuha ng kaukulang item mula sa listahan:

my $gappy = pack( 'cxs cxxx l!', $c1, $s, $c2, $l );

Tandaan ang "!" pagkatapos ng "l": Gusto naming tiyakin na nag-iimpake kami ng mahabang integer habang ito ay pinagsama-sama
ng aming C compiler. At kahit ngayon, gagana lamang ito para sa mga platform kung saan ang compiler
inaayos ang mga bagay tulad ng nasa itaas. At ang isang tao sa isang lugar ay may plataporma kung saan wala ito.
[Marahil ay isang Cray, kung saan ang mga "short", "int" at "long" ay lahat ay 8 byte. :-)]

Ang pagbibilang ng mga byte at panonood ng mga alignment sa mahahabang istruktura ay tiyak na isang drag. hindi ba
may paraan ba tayo na makagawa ng template gamit ang isang simpleng program? Narito ang isang C program na nagagawa
ang trick:

# isama
#isama

typedef struct {
char fc1;
maikling fs;
char fc2;
mahabang fl;
} gappy_t;

#define Pt(struct,field,tchar) \
printf("@%d%s", offsetof(struct,field), # tchar );

int main () {
Pt( gappy_t, fc1, c );
Pt( gappy_t, fs, s! );
Pt( gappy_t, fc2, c );
Pt( gappy_t, fl, l! );
printf("\n");
}

Ang linya ng output ay maaaring gamitin bilang isang template sa isang "pack" o "unpack" na tawag:

aking $gappy = pack( '@0c @2s! @4c @8l!', $c1, $s, $c2, $l );

Gee, isa pang template code - na parang kulang kami. Ngunit inililigtas ng "@" ang ating araw sa pamamagitan ng pagpapagana
sa amin upang tukuyin ang offset mula sa simula ng pack buffer hanggang sa susunod na item: Ito ay
ang halaga lamang ang "offsetof" macro (tinukoy sa " ") bumabalik kapag binigyan ng a
"struct" type at isa sa mga field name nito ("member-designator" sa C standardese).

Ang alinman sa paggamit ng mga offset o pagdaragdag ng "x" upang tulay ang mga puwang ay kasiya-siya. (Isipin mo na lang
ano ang mangyayari kung magbago ang istraktura.) Ang talagang kailangan natin ay isang paraan ng pagsasabi ng "laktawan bilang
maraming byte kung kinakailangan sa susunod na multiple ng N". Sa matatas na Templatese, sasabihin mo ito
na may "x!N" kung saan ang N ay pinalitan ng naaangkop na halaga. Narito ang susunod na bersyon ng aming
struct packaging:

my $gappy = pack( 'cx!2 scx!4 l!', $c1, $s, $c2, $l );

Tiyak na mas mabuti iyon, ngunit kailangan pa rin nating malaman kung gaano katagal ang lahat ng integer, at
malayo ang portability. Sa halip na 2, halimbawa, gusto naming sabihin na "gaano man kahaba ang isang maikli
ay". Ngunit ito ay maaaring gawin sa pamamagitan ng paglalagay ng naaangkop na pack code sa mga bracket: "[s]". Kaya,
narito ang pinakamahusay na magagawa natin:

my $gappy = pack( 'cx![s] scx![l!] l!', $c1, $s, $c2, $l );

Pakikitungo sa Endian-ness
Ngayon, isipin na gusto naming i-pack ang data para sa isang makina na may ibang byte-order.
Una, kailangan nating malaman kung gaano kalaki ang mga uri ng data sa target na makina.
Ipagpalagay natin na ang longs ay 32 bits ang lapad at ang shorts ay 16 bits ang lapad. Kaya mo naman
muling isulat ang template bilang:

my $gappy = pack( 'cx![s] scx![l] l', $c1, $s, $c2, $l );

Kung ang target na makina ay little-endian, maaari tayong sumulat:

my $gappy = pack( 'cx![s] s< cx![l] l<', $c1, $s, $c2, $l );

Pinipilit nitong maging little-endian ang maikli at mahahabang miyembro, at ayos lang kung ikaw
walang masyadong maraming miyembro ng struct. Ngunit maaari rin naming gamitin ang byte-order modifier sa a
pangkat at isulat ang sumusunod:

my $gappy = pack( '( cx![s] scx![l] l )<', $c1, $s, $c2, $l );

Ito ay hindi kasing-ikli tulad ng dati, ngunit ginagawa nitong mas malinaw na nilalayon nating magkaroon
little-endian byte-order para sa isang buong grupo, hindi lamang para sa mga indibidwal na template code. Maaari itong
maging mas nababasa at mas madaling mapanatili.

pagkakahanay, Kumuha 2
Natatakot ako na hindi pa tayo tapos sa alignment catch. Tumataas ang hydra
isa pang pangit na ulo kapag nag-pack ka ng mga arrays ng mga istraktura:

typedef struct {
maikling bilang;
char glyph;
} cell_t;

typedef cell_t buffer_t[BUFLEN];

Nasaan ang huli? Ang padding ay hindi kinakailangan bago ang unang field na "bilang", o sa pagitan
ito at ang susunod na field na "glyph", kaya bakit hindi na lang tayo mag-pack ng ganito:

# may mali dito:
pack( 's!a' x @buffer,
mapa{ ($_->{count}, $_->{glyph} ) } @buffer );

Naka-pack ito ng "3*@buffer" bytes, ngunit lumalabas na apat na beses ang laki ng "buffer_t"
"BUFLEN"! Ang moral ng kuwento ay ang kinakailangang pagkakahanay ng isang istraktura o array ay
pinalaganap sa susunod na mas mataas na antas kung saan kailangan nating isaalang-alang ang padding at ang dulo ng bawat
component din. Kaya ang tamang template ay:

pack( 's!ax' x @buffer,
mapa{ ($_->{count}, $_->{glyph} ) } @buffer );

pagkakahanay, Kumuha 3
At kahit na isinasaalang-alang mo ang lahat ng nasa itaas, pinapayagan pa rin ito ng ANSI:

typedef struct {
char foo[2];
} foo_t;

iba-iba ang laki. Ang hadlang sa pagkakahanay ng istraktura ay maaaring mas malaki kaysa sa alinman sa mga ito
mga elemento. [At kung sa tingin mo ay hindi ito nakakaapekto sa anumang bagay na karaniwan, putulin ang susunod
cellphone na nakikita mo. Marami ang may mga ARM core, at ang mga panuntunan sa istruktura ng ARM ay gumagawa ng "sizeof
(foo_t)" == 4]

giya para Gaano sa paggamit Sa kanila
Ang pamagat ng seksyong ito ay nagpapahiwatig ng pangalawang problema na maaari mong matamo sa maaga o huli
kapag nag-pack ka ng mga istrukturang C. Kung inaasahan ng function na balak mong tawagan ang isang, sabihin, "void *"
halaga, ikaw hindi maaari kumuha lang ng reference sa isang variable ng Perl. (Kahit na ang halaga na iyon
tiyak na isang memory address, hindi ito ang address kung saan naroroon ang mga nilalaman ng variable
nakaimbak.)

Ang template code na "P" ay nangangako na mag-impake ng "pointer sa isang nakapirming haba na string". Hindi ba ito ano
gusto namin? Subukan Natin:

# maglaan ng ilang storage at mag-pack ng pointer dito
my $memory = "\x00" x $size;
my $memptr = pack( 'P', $memory );

Ngunit maghintay: hindi ba ang "pack" ay nagbabalik lamang ng isang pagkakasunud-sunod ng mga byte? Paano natin maipapasa itong string ng
bytes sa ilang C code na umaasa sa isang pointer na, pagkatapos ng lahat, walang iba kundi isang numero? Ang
Ang sagot ay simple: Kailangan nating makuha ang numerong address mula sa mga byte na ibinalik ng "pack".

my $ptr = unpack( 'L!', $memptr );

Malinaw na ipinapalagay nito na posibleng mag-typecast ng isang pointer sa isang unsigned na mahaba at
vice versa, na madalas na gumagana ngunit hindi dapat kunin bilang isang unibersal na batas. - Ngayon na
mayroon kaming pointer na ito ang susunod na tanong ay: Paano natin ito magagamit nang mabuti? Kailangan namin ng tawag
sa ilang C function kung saan inaasahan ang isang pointer. Ang basahin(2) system call ang nasa isip:

ssize_t read(int fd, void *buf, size_t count);

Pagkatapos basahin ang perlfunc na nagpapaliwanag kung paano gamitin ang "syscall" maaari naming isulat ang Perl function na ito
pagkopya ng isang file sa karaniwang output:

nangangailangan ng 'syscall.ph'; # magpatakbo ng h2ph para mabuo ang file na ito
sub cat($){
aking $path = shift();
aking $size = -s $path;
my $memory = "\x00" x $size; # maglaan ng ilang memorya
my $ptr = unpack( 'L', pack( 'P', $memory ) );
bukas( F, $path ) || die("$path: hindi mabuksan ($!)\n" );
my $fd = fileno(F);
my $res = syscall( &SYS_read, fileno(F), $ptr, $size );
i-print ang $memorya;
malapit ( F );
}

Ito ay hindi isang ispesimen ng pagiging simple o isang huwaran ng portability ngunit ito ay naglalarawan
ang punto: Nagagawa naming lumabas sa likod ng mga eksena at ma-access ang Perl's kung hindi man ay binabantayang mabuti
alaala! (Mahalagang tala: Ang "syscall" ni Perl ay hindi kailangan mong bumuo ng mga pointer sa
paikot na daan na ito. Magpapasa ka lang ng string variable, at ipinapasa ni Perl ang address.)

Paano gumagana ang "unpack" na may "P"? Isipin ang ilang pointer sa buffer na malapit nang ma-unpack:
Kung hindi ito ang null pointer (na matalinong gagawa ng "undef" na halaga) mayroon kaming
panimulang address - ngunit ano? Walang paraan si Perl para malaman kung gaano katagal itong "fixed length
string" ay, kaya nasa sa iyo na tukuyin ang aktwal na laki bilang isang tahasang haba pagkatapos ng "P".

my $mem = "abcdefghijklmn";
print unpack( 'P5', pack( 'P', $mem ) ); # prints "abcde"

Bilang resulta, binabalewala ng "pack" ang anumang numero o "*" pagkatapos ng "P".

Ngayong nakita na natin si "P" sa trabaho, maaari na rin nating bigyan ng "p" ang isang whirl. Bakit kailangan natin ng a
pangalawang template code para sa pag-iimpake ng mga pointer sa lahat? Ang sagot ay nasa likod ng simpleng katotohanan
na ang isang "unpack" na may "p" ay nangangako ng null-terminated string na nagsisimula sa address na kinuha
mula sa buffer, at iyon ay nagpapahiwatig ng haba para sa data item na ibabalik:

my $buf = pack( 'p', "abc\x00efhijklmn" );
print unpack( 'p', $buf ); # prints "abc"

Kahit na ito ay apt na nakalilito: Bilang resulta ng haba na ipinahiwatig ng
ang haba ng string, isang numero pagkatapos ng pack code na "p" ay isang umuulit na bilang, hindi isang haba tulad ng pagkatapos
"P".

Gamit ang "pack(..., $x)" na may "P" o "p" upang makuha ang address kung saan ang $x ay aktwal na nakaimbak ay dapat
gamitin nang may pag-iingat. Isinasaalang-alang ng panloob na makinarya ng Perl ang kaugnayan sa pagitan ng a
variable at ang address na iyon bilang sarili nitong pribadong bagay at wala talagang pakialam sa amin
nakakuha ng kopya. Samakatuwid:

· Huwag gumamit ng "pack" na may "p" o "P" para makuha ang address ng variable na dapat pumunta
wala sa saklaw (at sa gayon ay pinalaya ang memorya nito) bago ka tapos sa paggamit ng
memorya sa address na iyon.

· Maging maingat sa mga pagpapatakbo ng Perl na nagbabago sa halaga ng variable. Nagdadagdag
ang isang bagay sa variable, halimbawa, ay maaaring mangailangan ng muling paglalagay ng imbakan nito,
nag-iiwan sa iyo ng isang pointer sa walang tao na lupain.

· Huwag isipin na maaari mong makuha ang address ng isang Perl variable kapag ito ay naka-imbak bilang isang
integer o dobleng numero! Ang "pack('P', $x)" ay pipilitin ang panloob ng variable
representasyon sa string, tulad ng kung isinulat mo ang isang bagay tulad ng "$x .= ''".

Ito ay ligtas, gayunpaman, sa P- o p-pack ng isang string na literal, dahil ang Perl ay naglalaan lamang ng isang
anonymous na variable.

Mag-impake Mga Recipe


Narito ang isang koleksyon ng (posibleng) kapaki-pakinabang na mga de-latang recipe para sa "pack" at "unpack":

# I-convert ang IP address para sa mga function ng socket
pack( "C4", split /\./, "123.4.5.6" );

# Bilangin ang mga bit sa isang tipak ng memorya (hal. isang piling vector)
unpack( '%32b*', $mask );

# Tukuyin ang endianness ng iyong system
$is_little_endian = unpack( 'c', pack( 's', 1 ) );
$is_big_endian = unpack( 'xc', pack( 's', 1 ) );

# Tukuyin ang bilang ng mga bit sa isang native integer
$bits = unpack( '%32I!', ~0 );

# Maghanda ng argumento para sa nanosleep system call
aking $timespec = pack( 'L!L!', $secs, $nanosecs );

Para sa isang simpleng memory dump, i-unpack namin ang ilang byte sa kasing dami ng mga pares ng hex digit, at
gumamit ng "mapa" upang mahawakan ang tradisyonal na espasyo - 16 bytes sa isang linya:

aking $i;
print map(++$i % 16 ? "$_ " : "$_\n",
i-unpack( 'H2' x haba( $mem ), $mem ) ),
haba( $mem ) % 16 ? "\n" : '';

Mga nakakatawa seksyon


# Kinukuha ang mga digit nang wala saan...
print unpack( 'C', pack( 'x' ) ),
i-unpack( '%B*', pack( 'A' ) ),
i-unpack( 'H', pack( 'A' ) ),
i-unpack( 'A', unpack( 'C', pack( 'A' ) ) ), "\n";

# Isa para sa kalsada ;-)
my $advice = pack( 'all u can in a van' );

May-akda


Simon Cozens at Wolfgang Laun.

Gumamit ng perlpacktut online gamit ang mga serbisyo ng onworks.net


Mga Libreng Server at Workstation

Mag-download ng Windows at Linux apps

  • 1
    OfficeFloor
    OfficeFloor
    Nagbibigay ang OfficeFloor ng inversion ng
    kontrol ng pagkabit, kasama ang: - dependency
    iniksyon - pagpapatuloy ng iniksyon -
    thread injection Para sa karagdagang impormasyon
    bisitahin ang...
    I-download ang OfficeFloor
  • 2
    DivKit
    DivKit
    Ang DivKit ay isang open source na Server-Driven
    Framework ng UI (SDUI). Pinapayagan ka nitong
    ilunsad ang mga update mula sa server sa
    iba't ibang bersyon ng app. Gayundin, maaari itong maging
    ginagamit para...
    I-download ang DivKit
  • 3
    subconverter
    subconverter
    Utility upang i-convert sa pagitan ng iba't-ibang
    format ng subscription. Mga gumagamit ng Shadowrocket
    dapat gumamit ng ss, ssr o v2ray bilang target.
    Maaari mong idagdag ang &remark= sa
    Telegram-like na HT...
    I-download ang subconverter
  • 4
    SWASH
    SWASH
    Ang SWASH ay isang pangkalahatang layunin na numero
    tool para sa pagtulad sa hindi matatag,
    non-hydrostatic, free-surface,
    rotational flow at transport phenomena
    sa tubig sa baybayin bilang ...
    I-download ang SWASH
  • 5
    VBA-M (Naka-archive - Ngayon sa Github)
    VBA-M (Naka-archive - Ngayon sa Github)
    Lumipat ang proyekto sa
    https://github.com/visualboyadvance-m/visualboyadvance-m
    Mga Tampok:Paglikha ng cheatsave statesmulti
    system, sumusuporta sa gba, gbc, gb, sgb,
    sgb2Tu...
    I-download ang VBA-M (Naka-archive - Ngayon sa Github)
  • 6
    Stacer
    Stacer
    Linux System Optimizer at Pagsubaybay
    Github Repository:
    https://github.com/oguzhaninan/Stacer.
    Audience: Mga End User/Desktop. Gumagamit
    interface: Qt. Programming La...
    I-download ang Stacer
  • Marami pa »

Linux command

Ad