InglêsFrancêsEspanhol

favicon do OnWorks

perlpacktut - Online na Nuvem

Execute perlpacktut no provedor de hospedagem gratuita OnWorks no Ubuntu Online, Fedora Online, emulador online do Windows ou emulador online do MAC OS

Este é o comando perlpacktut que pode ser executado no provedor de hospedagem gratuita OnWorks usando uma de nossas várias estações de trabalho online gratuitas, como Ubuntu Online, Fedora Online, emulador online do Windows ou emulador online do MAC OS

PROGRAMA:

NOME


perlpacktut - tutorial sobre "empacotar" e "descompactar"

DESCRIÇÃO


"pack" e "unpack" são duas funções para transformar dados de acordo com um
template, entre a forma protegida que o Perl armazena valores e alguma representação bem definida
como pode ser necessário no ambiente de um programa Perl. Infelizmente, eles também são dois
das funções mais incompreendidas e muitas vezes negligenciadas que o Perl fornece. Isto
tutorial irá desmistificá-los para você.

A Basico Princípio


A maioria das linguagens de programação não abriga a memória onde as variáveis ​​são armazenadas. Em C, para
instância, você pode pegar o endereço de alguma variável, e o operador "sizeof" lhe diz
quantos bytes são alocados para a variável. Usando o endereço e o tamanho, você pode
acesse o armazenamento para o conteúdo do seu coração.

Em Perl, você simplesmente não pode acessar a memória aleatoriamente, mas a estrutura e representação
conversão fornecida por "pack" e "unpack" é uma excelente alternativa. O pacote"
função converte valores em uma seqüência de bytes contendo representações de acordo com um
determinada especificação, o chamado argumento "modelo". "descompactar" é o processo inverso,
derivando alguns valores do conteúdo de uma string de bytes. (Atenção, no entanto, que
nem tudo o que foi empacotado pode ser desempacotado perfeitamente - uma experiência muito comum, pois
viajantes experientes provavelmente confirmarão.)

Por que, você pode perguntar, você precisaria de um pedaço de memória contendo alguns valores em binário
representação? Uma boa razão é o acesso de entrada e saída a algum arquivo, dispositivo ou
conexão de rede, em que esta representação binária é forçada a você ou será
dar-lhe algum benefício no processamento. Outra causa é passar dados para alguma chamada de sistema
que não está disponível como uma função Perl: "syscall" requer que você forneça parâmetros
armazenado da maneira que acontece em um programa C. Até mesmo o processamento de texto (como mostrado na próxima
seção) pode ser simplificada com o uso criterioso dessas duas funções.

Para ver como funciona o (des)packing, vamos começar com um código de modelo simples onde a conversão
está em marcha lenta: entre o conteúdo de uma sequência de bytes e uma sequência de caracteres hexadecimais
dígitos. Vamos usar "unpack", já que isso provavelmente irá lembrá-lo de um programa de despejo, ou algum
última mensagem desesperada programas infelizes costumam jogar em você antes de expirarem
para o azul selvagem além. Assumindo que a variável $mem contém uma sequência de bytes que
gostaríamos de inspecionar sem assumir nada sobre seu significado, podemos escrever

meu($hex) = descompactar('H*', $mem);
imprima "$hex\n";

após o que podemos ver algo assim, com cada par de dígitos hexadecimais correspondendo a
um byte:

41204d414e204120504c414e20412043414e414c2050414e414d41

O que havia neste pedaço de memória? Números, caracteres ou uma mistura de ambos? Assumindo que
estamos em um computador onde a codificação ASCII (ou algo semelhante) é usada: valores hexadecimais em
o intervalo 0x40 - 0x5A indica uma letra maiúscula e 0x20 codifica um espaço. Então nós podemos
suponha que é um pedaço de texto, que alguns são capazes de ler como um tablóide; mas outros vão
tem que pegar uma tabela ASCII e reviver aquela sensação de primeira série. Não se importando também
muito sobre como ler isso, notamos que "descompactar" com o código de modelo "H"
converte o conteúdo de uma sequência de bytes na notação hexadecimal habitual.
Como "uma sequência de" é uma indicação bastante vaga de quantidade, "H" foi definido para
converter apenas um único dígito hexadecimal, a menos que seja seguido por uma contagem repetida. Um
asterisco para a contagem de repetição significa usar o que resta.

A operação inversa - empacotando o conteúdo de bytes de uma string de dígitos hexadecimais - é
tão facilmente escrito. Por exemplo:

meus $s = pack('H2' x 10, 30..39);
imprima "$s\n";

Como alimentamos uma lista de dez strings hexadecimais de 2 dígitos para "pack", o modelo de pacote
deve conter dez códigos de pacote. Se isso for executado em um computador com codificação de caracteres ASCII,
ele imprimirá 0123456789.

Embalagem Texto


Vamos supor que você tenha que ler um arquivo de dados como este:

Data |Descrição | Receita | Despesa
01/24/2001 Zed's Camel Emporium 1147.99
01/28/2001 Pulverizador 24.99
01/29/2001 Passeios de camelo para turistas 235.00

Como fazemos isso? Você pode pensar primeiro em usar "split"; no entanto, uma vez que o "split" colapsa
campos em branco, você nunca saberá se um registro foi receita ou despesa. Ops. Nós vamos,
você sempre pode usar "substr":

enquanto (<>) {
meu $data = substr($_, 0, 11);
meu $desc = substr($_, 12, 27);
minha $renda = substr($_, 40, 7);
meu $gasto = substr($_, 52, 7);
...
}

Não é realmente um barril de risadas, é? Na verdade, é pior do que parece; a
olhos de águia podem notar que o primeiro campo deve ter apenas 10 caracteres de largura, e o
erro se propagou através dos outros números - que tivemos que contar à mão.
Portanto, é propenso a erros e terrivelmente hostil.

Ou talvez possamos usar expressões regulares:

enquanto (<>) {
meu($data, $desc, $renda, $despesa) =
m|(\d\d/\d\d/\d{4}) (.{27}) (.{7})(.*)|;
...
}

Urgh. Bem, é um pouco melhor, mas - bem, você gostaria de manter isso?

Ei, Perl não deveria facilitar esse tipo de coisa? Bem, ele faz, se você usar o
ferramentas certas. "pack" e "unpack" são projetados para ajudá-lo ao lidar com
dados de largura como o acima. Vamos dar uma olhada em uma solução com "unpack":

enquanto (<>) {
my($data, $desc, $renda, $gasto) = unpack("A10xA27xA7A*", $_);
...
}

Isso parece um pouco melhor; mas temos que desmontar esse modelo estranho. Onde eu puxei
isso fora?

OK, vamos dar uma olhada em alguns de nossos dados novamente; na verdade, incluiremos os cabeçalhos e um
régua acessível para que possamos acompanhar onde estamos.

1 2 3 4 5
1234567890123456789012345678901234567890123456789012345678
Data |Descrição | Receita | Despesa
01/28/2001 Pulverizador 24.99
01/29/2001 Passeios de camelo para turistas 235.00

A partir disso, podemos ver que a coluna de data se estende da coluna 1 à coluna 10 - dez
caracteres largos. O "pack"-ese para "personagem" é "A", e dez deles são "A10". Então se
só queríamos extrair as datas, poderíamos dizer o seguinte:

meu($data) = descompactar("A10", $_);

Certo, o que vem a seguir? Entre a data e a descrição há uma coluna em branco; nós queremos pular
sobre isso. O modelo "x" significa "pular para frente", então queremos um desses. A seguir, temos
outro lote de caracteres, de 12 a 38. São mais 27 caracteres, daí "A27". (Não
faça o erro da cerca - existem 27 caracteres entre 12 e 38, não 26. Conte-os!)

Agora pulamos outro caractere e pegamos os próximos 7 caracteres:

meu($data,$descrição,$renda) = unpack("A10xA27xA7", $_);

Agora vem a parte inteligente. Linhas em nosso livro que são apenas receitas e não despesas
pode terminar na coluna 46. Portanto, não queremos dizer ao nosso padrão "unpack" que necessidade para
encontre outros 12 caracteres; vamos apenas dizer "se sobrar alguma coisa, pegue". Como você
pode adivinhar a partir de expressões regulares, é isso que o "*" significa: "use tudo
remanescente".

· Esteja avisado, porém, que diferentemente das expressões regulares, se o modelo "descompactar" não
corresponder aos dados recebidos, Perl gritará e morrerá.

Assim, juntando tudo:

meu ($data, $descrição, $renda, $despesa) =
unpack("A10xA27xA7xA*", $_);

Agora, esses são nossos dados analisados. Suponho que o que podemos querer fazer agora é totalizar nossa renda
e despesas, e adicionar outra linha ao final do nosso livro - no mesmo formato -
dizendo quanto arrecadamos e quanto gastamos:

enquanto (<>) {
meu ($data, $desc, $renda, $despesa) =
unpack("A10xA27xA7xA*", $_);
$tot_income += $renda;
$tot_despesas += $despesas;
}

$tot_income = sprintf("%.2f", $tot_income); # Coloque-os em
$tot_expend = sprintf("%.2f", $tot_expend); # formato "financeiro"

$data = POSIX::strftime("%m/%d/%Y", hora local);

#Bom, vamos:

print pack("A10xA27xA7xA*", $data, "Totais",
$tot_income, $tot_despesa);

Ah, hum. Isso não funcionou muito bem. Vamos ver o que aconteceu:

01/24/2001 Zed's Camel Emporium 1147.99
01/28/2001 Pulverizador 24.99
01/29/2001 Passeios de camelo para turistas 1235.00
03/23/2001Totais 1235.001172.98

OK, é um começo, mas o que aconteceu com os espaços? Colocamos "x", não foi? Não deveria
passe à frente? Vejamos o que "pack" em perlfunc diz:

x Um byte nulo.

Urgh. Não admira. Há uma grande diferença entre "um byte nulo", caractere zero e "um
space", caractere 32. Perl colocou algo entre a data e a descrição - mas
infelizmente não podemos ver!

O que realmente precisamos fazer é expandir a largura dos campos. O formato "A" preenche qualquer
caracteres inexistentes com espaços, para que possamos usar os espaços adicionais para alinhar nossos
campos, assim:

print pack("A11 A28 A8 A*", $data, "Totais",
$tot_income, $tot_despesa);

(Observe que você pode colocar espaços no modelo para torná-lo mais legível, mas eles não
traduza para espaços na saída.) Aqui está o que temos desta vez:

01/24/2001 Zed's Camel Emporium 1147.99
01/28/2001 Pulverizador 24.99
01/29/2001 Passeios de camelo para turistas 1235.00
03/23/2001 Totais 1235.00 1172.98

Isso é um pouco melhor, mas ainda temos a última coluna que precisa ser movida ainda mais
sobre. Existe uma maneira fácil de consertar isso: infelizmente, não podemos fazer o "pack" certo-
justificar nossos campos, mas podemos obter "sprintf" para fazer isso:

$tot_income = sprintf("%.2f", $tot_income);
$tot_expend = sprintf("%12.2f", $tot_expend);
$data = POSIX::strftime("%m/%d/%Y", hora local);
print pack("A11 A28 A8 A*", $data, "Totais",
$tot_income, $tot_despesa);

Desta vez temos a resposta certa:

01/28/2001 Pulverizador 24.99
01/29/2001 Passeios de camelo para turistas 1235.00
03/23/2001 Totais 1235.00 1172.98

Então é assim que consumimos e produzimos dados de largura fixa. Vamos recapitular o que vimos
"pack" e "unpack" até agora:

· Use "pack" para ir de vários dados para uma versão de largura fixa; use "descompactar"
para transformar uma string de formato de largura fixa em vários dados.

· O formato do pacote "A" significa "qualquer caractere"; se você está "fazendo as malas" e ficou sem
coisas para empacotar, "empacotar" preencherá o resto com espaços.

· "x" significa "pular um byte" ao "descompactar"; quando "embalar", significa "introduzir um null
byte" - provavelmente não é isso que você quer dizer se estiver lidando com texto simples.

· Você pode seguir os formatos com números para dizer quantos caracteres devem ser afetados
por esse formato: "A12" significa "tomar 12 caracteres"; "x6" significa "pular 6 bytes" ou
"caractere 0, 6 vezes".

· Em vez de um número, você pode usar "*" para significar "consumir todo o resto".

Aviso: ao empacotar vários dados, "*" significa apenas "consumir todos os
parte atual dos dados". Isso quer dizer

pack("A*A*", $um, $dois)

empacota todos os $um no primeiro "A*" e depois todos os $dois no segundo. Isto é um
princípio geral: cada caractere de formato corresponde a um dado a ser
"embalado".

Embalagem Números


Tanto para dados textuais. Vamos para as coisas carnudas que "embalar" e "desempacotar" são melhores
at: manipulação de formatos binários para números. É claro que não existe apenas um formato binário
- a vida seria muito simples - mas Perl fará todo o trabalho meticuloso para você.

Inteiros
Embalar e desempacotar números implica a conversão de e para alguns específico binário
representação. Deixando de lado os números de ponto flutuante por enquanto, o
propriedades de qualquer representação são:

· o número de bytes usados ​​para armazenar o inteiro,

· se o conteúdo é interpretado como um número assinado ou não assinado,

· a ordenação dos bytes: se o primeiro byte é o byte menos ou mais significativo (ou:
little-endian ou big-endian, respectivamente).

Então, por exemplo, para empacotar 20302 em um inteiro de 16 bits assinado no
representação que você escreve

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

Novamente, o resultado é uma string, agora contendo 2 bytes. Se você imprimir esta string (que é,
geralmente, não recomendado) você pode ver "ON" ou "NO" (dependendo do byte do seu sistema
ordenação) - ou algo totalmente diferente se o seu computador não usar caracteres ASCII
codificação. Descompactar $ps com o mesmo template retorna o valor inteiro original:

meu($s) = descompactar('s', $ps);

Isso é verdade para todos os códigos de modelo numéricos. Mas não espere milagres: se o embalado
valor excede a capacidade de bytes alocada, os bits de ordem alta são descartados silenciosamente e
descompactar certamente não será capaz de retirá-los de algum chapéu mágico. E, quando você embala
usando um código de modelo assinado, como "s", um valor em excesso pode resultar no bit de sinal
sendo definido e descompactar isso retornará um valor negativo de maneira inteligente.

16 bits não o levarão muito longe com números inteiros, mas há "l" e "L" para sinais e
inteiros de 32 bits sem sinal. E se isso não for suficiente e seu sistema suportar 64 bits
inteiros você pode empurrar os limites muito mais perto do infinito com os códigos de pacote "q" e "Q". UMA
exceção notável é fornecida pelos códigos de pacote "i" e "I" para inteiros assinados e não assinados
da variedade "personalizado local": esse número inteiro ocupará tantos bytes quanto um C local
compilador retorna para "sizeof(int)", mas usará at mínimo 32 bits.

Cada um dos códigos de pacote inteiro "sSlLqQ" resulta em um número fixo de bytes, não importa
onde você executa seu programa. Isso pode ser útil para alguns aplicativos, mas não
fornecer uma maneira portátil de passar estruturas de dados entre programas Perl e C (limitado a
acontece quando você chama extensões XS ou a função Perl "syscall"), ou quando você lê ou
escrever arquivos binários. O que você precisará neste caso são códigos de modelo que dependem do que
seu compilador C local compila quando você codifica "short" ou "unsigned long", por exemplo.
Esses códigos e seus comprimentos de byte correspondentes são mostrados na tabela abaixo. Desde o
O padrão C deixa muita margem de manobra em relação aos tamanhos relativos desses tipos de dados,
os valores reais podem variar, e é por isso que os valores são dados como expressões em C e Perl.
(Se você quiser usar valores de %Config em seu programa, você deve importá-lo com "use
Configuração".)

comprimento de byte sem sinal assinado em C comprimento de byte em Perl
e! S! sizeof(curto) $Config{tamanho curto}
eu! EU! sizeof(int) $Config{intsize}
eu! EU! sizeof(long) $Config{longsize}
q! P! sizeof(long long) $Config{longlongsize}

O "eu!" e eu!" os códigos não são diferentes de "i" e "I"; eles são tolerados para
perfeição.

Desempacotando a Pilha quadro
A solicitação de uma ordenação de bytes específica pode ser necessária quando você trabalha com dados binários
vindo de alguma arquitetura específica, enquanto seu programa pode ser executado em um ambiente totalmente
sistema diferente. Como exemplo, suponha que você tenha 24 bytes contendo um quadro de pilha como ele
acontece em um Intel 8086:

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

Primeiro, notamos que esta CPU de 16 bits consagrada pelo tempo usa a ordem little-endian, e é por isso que
o byte de ordem inferior é armazenado no endereço inferior. Para descompactar esse short (sem assinatura), vamos
tem que usar o código "v". Uma contagem repetida descompacta todos os 12 shorts:

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

Alternativamente, poderíamos ter usado "C" para descompactar os registradores de bytes acessíveis individualmente
FL, FH, AL, AH, etc.:

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

Seria bom se pudéssemos fazer isso de uma só vez: descompactar um short, voltar um pouco,
e então descompacte 2 bytes. Desde Perl is legal, ele oferece o código de modelo "X" para fazer backup
um byte. Juntando tudo isso, podemos agora escrever:

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

(A construção desajeitada do modelo pode ser evitada - apenas continue lendo!)

Nós nos esforçamos para construir o modelo para que ele corresponda ao conteúdo do nosso
Suavizador de quadros. Caso contrário, obteríamos valores indefinidos ou "descompactar" não poderia descompactar
tudo. Se "pack" ficar sem itens, ele fornecerá strings nulas (que são forçadas a
zeros sempre que o código do pacote diz isso).

Como funciona o dobrador de carta de canal para Comer an ovo on a Líquido
O código do pacote para big-endian (byte de alta ordem no endereço mais baixo) é "n" para 16 bits e
"N" para inteiros de 32 bits. Você usa esses códigos se souber que seus dados vêm de um
arquitetura compatível, mas, surpreendentemente, você também deve usar esses códigos de pacote se
você troca dados binários, pela rede, com algum sistema que você conhece ao lado
nada sobre. A razão simples é que esta ordem foi escolhida como a rede ordem,
e todos os programas que temem os padrões devem seguir essa convenção. (Isto é, obviamente, um
forte apoio para um dos partidos liliputianos e pode muito bem influenciar a política
desenvolvimento lá.) Então, se o protocolo espera que você envie uma mensagem enviando o
comprimento primeiro, seguido por apenas tantos bytes, você poderia escrever:

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

ou mesmo:

meu $buf = pack( 'NA*', comprimento( $msg ), $msg );

e passe $buf para sua rotina de envio. Alguns protocolos exigem que a contagem inclua
o comprimento da contagem em si: em seguida, basta adicionar 4 ao comprimento dos dados. (Mas certifique-se de ler
"Comprimentos e larguras" antes de realmente codificar isso!)

Ordem de bytes modificadores
Nas seções anteriores aprendemos como usar "n", "N", "v" e "V" para empacotar e desempacotar
inteiros com ordem de bytes big- ou little-endian. Embora isso seja bom, ainda é bastante
limitado porque deixa de fora todos os tipos de inteiros com sinal, bem como inteiros de 64 bits. Por
Por exemplo, se você quiser descompactar uma sequência de inteiros big-endian de 16 bits assinados em um
maneira independente de plataforma, você teria que escrever:

my @data = descompactar 's*', compactar 'S*', descompactar 'n*', $buf;

Isso é feio. A partir do Perl 5.9.2, há uma maneira muito melhor de expressar seu desejo por um
certa ordem de bytes: os modificadores ">" e "<". ">" é o modificador big-endian, enquanto "<"
é o modificador little-endian. Usando-os, poderíamos reescrever o código acima como:

meu @data = descompacte 's>*', $buf;

Como você pode ver, a "grande extremidade" da seta toca o "s", que é uma boa maneira de
lembre-se que ">" é o modificador big-endian. O mesmo obviamente funciona para "<", onde o
"pequena extremidade" toca o código.

Você provavelmente achará esses modificadores ainda mais úteis se tiver que lidar com grandes ou
estruturas C little-endian. Certifique-se de ler "Embalando e desempacotando estruturas C" para mais
naquilo.

Flutuante ponto Números
Para empacotar números de ponto flutuante, você pode escolher entre os códigos de pacote "f", "d",
"F" e "D". "f" e "d" empacotam em (ou desempacotam) precisão simples ou precisão dupla
representação fornecida pelo seu sistema. Se seus sistemas suportarem, "D" pode ser
usado para compactar e descompactar valores ("long double"), que podem oferecer ainda mais resolução do que
"f" ou "d". Note que e guarante que os mesmos estão diferente longo duplo formatos.

"F" empacota um "NV", que é o tipo de ponto flutuante usado internamente pelo Perl.

Não existe representação de rede para reais, então se você quiser enviar seu
números reais através dos limites do computador, é melhor manter a representação de texto,
possivelmente usando o formato float hexadecimal (evitando a perda de conversão decimal), a menos que
você tem certeza absoluta do que está do outro lado da linha. Para o ainda mais
aventureiro, você pode usar os modificadores de ordem de bytes da seção anterior também em
códigos de ponto flutuante.

Exótico Modelos


Pouco Cordas
Bits são os átomos no mundo da memória. O acesso a bits individuais pode ter que ser usado
seja como último recurso ou porque é a maneira mais conveniente de lidar com seus dados. Mordeu
string (des)packing converte entre strings contendo uma série de 0 e 1 caracteres e
uma sequência de bytes, cada um contendo um grupo de 8 bits. Isso é quase tão simples quanto
sons, exceto que há duas maneiras de o conteúdo de um byte ser escrito como um bit
corda. Vamos dar uma olhada em um byte anotado:

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

Está comendo ovos de novo: Alguns pensam que como uma pequena string isso deveria ser escrito
"10001100" ou seja, começando com o bit mais significativo, outros insistem em "00110001".
Bem, Perl não é tendencioso, então é por isso que temos dois códigos de string de bits:

$byte = pack('B8', '10001100'); #começa com MSB
$byte = pack('b8', '00110001'); #começa com LSB

Não é possível compactar ou descompactar campos de bits - apenas bytes integrais. "embalar" sempre
começa no próximo limite de byte e "arredonda" para o próximo múltiplo de 8 adicionando zero
bits conforme necessário. (Se você quiser campos de bits, há "vec" em perlfunc. Ou você pode
implementar a manipulação de campos de bits no nível da cadeia de caracteres, usando split, substr e
concatenação em cadeias de bits descompactadas.)

Para ilustrar a descompactação de strings de bits, vamos decompor um registrador de status simples (um "-"
significa um bit "reservado"):

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

A conversão desses dois bytes em uma string pode ser feita com o modelo de descompactação 'b16'. Para
obter os valores de bits individuais da string de bits que usamos "split" com o "empty"
padrão separador que disseca em caracteres individuais. Valores de bits do
posições "reservadas" são simplesmente atribuídas a "undef", uma notação conveniente para "eu não
cuidado para onde isso vai".

($carry, undef, $paridade, undef, $auxcarry, undef, $zero, $sign,
$trace, $interrupção, $direção, $overflow) =
split( //, unpack( 'b16', $status ) );

Poderíamos ter usado um modelo de descompactação 'b12' também, já que os últimos 4 bits podem ser
ignorado de qualquer maneira.

Uuencoding
Outro estranho no alfabeto do modelo é "u", que embala uma "string uuencoded".
("uu" é a abreviação de Unix-to-Unix.) É provável que você nunca precise dessa codificação
técnica que foi inventada para superar as deficiências da transmissão antiquada
mídias que não suportam outros dados ASCII simples. A receita essencial é simples:
Pegue três bytes, ou 24 bits. Divida-os em 4 pacotes de seis, adicionando um espaço (0x20) a cada um.
Repita até que todos os dados estejam misturados. Dobre grupos de 4 bytes em linhas não maiores que
60 e decore-os na frente com a contagem de bytes original (incrementada em 0x20) e um "\n"
no fim. - O chef "pack" irá preparar isso para você, a la minuto, quando você selecionar o pacote
código "u" no menu:

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

Uma contagem de repetição após "u" define o número de bytes a serem colocados em uma linha codificada com uu, que é
o máximo de 45 por padrão, mas pode ser definido como algum múltiplo inteiro (menor) de
três. "unpack" simplesmente ignora a contagem de repetições.

fazendo Somas
Um código de modelo ainda mais estranho é "%"número>. Primeiro, porque é usado como prefixo para
algum outro código de modelo. Segundo, porque não pode ser usado em "pack" e terceiro,
em "unpack", não retorna os dados conforme definido pelo código do modelo que o precede. Em vez de
ele vai te dar um número inteiro de número bits que são calculados a partir do valor de dados fazendo
somas. Para códigos numéricos de descompactação, nenhum grande feito é alcançado:

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

Para valores de string, "%" retorna a soma dos valores de byte, economizando o problema de uma soma
loop com "substr" e "ord":

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

Embora o código "%" esteja documentado como retornando uma "soma de verificação": não confie em
tais valores! Mesmo quando aplicados a um pequeno número de bytes, eles não garantem uma
distância de Hamming perceptível.

Em conexão com "b" ou "B", "%" simplesmente adiciona bits, e isso pode ser bem utilizado para
conte os bits definidos de forma eficiente:

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

E um bit de paridade par pode ser determinado assim:

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

Unicode
Unicode é um conjunto de caracteres que pode representar a maioria dos caracteres na maioria dos
idiomas, oferecendo espaço para mais de um milhão de caracteres diferentes. Unicode 3.1 especifica
94,140 caracteres: Os caracteres latinos básicos são atribuídos aos números de 0 a 127.
Latin-1 Suplemento com caracteres que são usados ​​em vários idiomas europeus está no
próximo intervalo, até 255. Depois de mais algumas extensões latinas, encontramos os conjuntos de caracteres de
línguas que usam alfabetos não romanos, intercalados com uma variedade de conjuntos de símbolos, como
símbolos de moeda, Zapf Dingbats ou Braille. (Você pode querer visitar
<http://www.unicode.org/> para dar uma olhada em alguns deles - meus favoritos pessoais são Telugu
e Kannada.)

Os conjuntos de caracteres Unicode associam caracteres a inteiros. Codificando esses números em
um número igual de bytes seria mais do que o dobro dos requisitos para armazenar textos escritos
em alfabetos latinos. A codificação UTF-8 evita isso armazenando os mais comuns (de um
ponto de vista ocidental) caracteres em um único byte enquanto codifica os mais raros em três
ou mais bytes.

Perl usa UTF-8, internamente, para a maioria das strings Unicode.

Então, o que isso tem a ver com "pacote"? Bem, se você quiser compor uma string Unicode
(que é codificado internamente como UTF-8), você pode fazer isso usando o código de modelo "U". Como um
Por exemplo, vamos produzir o símbolo da moeda Euro (número de código 0x20AC):

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

Inspecionar $UTF8{Euro} mostra que ele contém 3 bytes: "\xe2\x82\xac". no entanto
contém apenas 1 caractere, número 0x20AC. A viagem de ida e volta pode ser completada com "unpack":

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

A descompactação usando o código de modelo "U" também funciona em cadeias de bytes codificadas em UTF-8.

Normalmente, você desejará compactar ou descompactar strings UTF-8:

# compactar e descompactar o alfabeto hebraico
my $alefbet = pack( 'U*', 0x05d0..0x05ea );
my @hebrew = unpack('U*', $utf);

Observe: no caso geral, é melhor usar Encode::decode_utf8 para decodificar um
Cadeia de bytes codificada em UTF-8 para uma cadeia de caracteres Perl Unicode e Encode::encode_utf8 para codificar um
Cadeia Perl Unicode para bytes UTF-8. Essas funções fornecem meios de lidar com bytes inválidos
sequências e geralmente têm uma interface mais amigável.

Outro Portátil Binário Codificação
O código do pacote "w" foi adicionado para suportar um esquema de codificação de dados binários portátil que
vai muito além de números inteiros simples. (Detalhes podem ser encontrados emhttp://Casbah.org/>, o Escaravelho
projeto.) Um inteiro sem sinal comprimido BER (Binary Encoded Representation) armazena a base
128 dígitos, dígito mais significativo primeiro, com o menor número de dígitos possível. Bit oito (o
bit alto) é definido em cada byte, exceto no último. Não há limite de tamanho para a codificação BER, mas
Perl não vai a extremos.

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

Um dump hexadecimal de $ berbuf, com espaços inseridos nos lugares certos, mostra 01 8100 8101
81807F. Como o último byte é sempre menor que 128, "unpack" sabe onde parar.

Modelo Agrupamento


Antes do Perl 5.8, as repetições de templates tinham que ser feitas pela multiplicação "x" de
cadeias de modelo. Agora existe uma maneira melhor, pois podemos usar os códigos de pacote "(" e ")"
combinado com uma contagem de repetição. O modelo "unpack" do exemplo Stack Frame pode
simplesmente ser escrito assim:

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

Vamos explorar um pouco mais esse recurso. Começaremos com o equivalente a

join( '', map( substr( $_, 0, 1 ), @str ) )

que retorna uma string que consiste no primeiro caractere de cada string. Usando pacote, nós
pode escrever

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

ou, porque uma contagem de repetição "*" significa "repetir quantas vezes for necessário", simplesmente

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

(Observe que o modelo "A*" teria compactado apenas $str[0] em tamanho completo.)

Para empacotar datas armazenadas como trigêmeos ( dia, mês, ano ) em uma matriz @dates em uma sequência
de byte, byte, inteiro curto podemos escrever

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

Para trocar pares de caracteres em uma string (com comprimento uniforme), pode-se usar vários
técnicas. Primeiro, vamos usar "x" e "X" para pular para frente e para trás:

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

Também podemos usar "@" para pular para um deslocamento, sendo 0 a posição em que estávamos quando o
último "(" foi encontrado:

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

Finalmente, há também uma abordagem totalmente diferente ao desembalar os shorts big endian e
empacotando-os na ordem inversa de bytes:

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

comprimentos e larguras


Tanga comprimentos
Na seção anterior, vimos uma mensagem de rede que foi construída prefixando o
comprimento da mensagem binária para a mensagem real. Você verá que empacotar um comprimento seguido por
tantos bytes de dados é uma receita usada com frequência, pois anexar um byte nulo não funcionará
se um byte nulo pode fazer parte dos dados. Aqui está um exemplo onde ambas as técnicas são usadas:
após duas strings terminadas em nulo com endereço de origem e destino, uma mensagem curta (para
um telefone celular) é enviado após um byte de comprimento:

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

Descompactar esta mensagem pode ser feito com o mesmo modelo:

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

Há uma armadilha sutil à espreita: adicionar outro campo após a mensagem curta
(na variável $sm) está tudo bem ao empacotar, mas isso não pode ser descompactado ingenuamente:

# embalar uma mensagem
my $msg = pack('Z*Z*CA*C', $src, $dst, comprimento($sm), $sm, $prio);

# descompactação falha - $prio permanece indefinido!
( $src, $dst, $len, $sm, $prio) = unpack('Z*Z*CA*C', $msg);

O código do pacote "A*" engole todos os bytes restantes, e $prio permanece indefinido! Antes de nós
deixe a decepção abater o moral: Perl tem o trunfo para fazer esse truque também,
apenas um pouco mais na manga. Vê isto:

# empacota uma mensagem: ASCIIZ, ASCIIZ, comprimento/string, byte
my $msg = pack( 'Z* Z* C/A* C', $src, $dst, $sm, $prio);

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

A combinação de dois códigos de pacote com uma barra ("/") os associa a um único valor do
lista de argumentos. Em "pack", o comprimento do argumento é tomado e empacotado de acordo com o
primeiro código enquanto o próprio argumento é adicionado após ser convertido com o código do modelo
após a barra. Isso nos poupa o trabalho de inserir a chamada "comprimento", mas está em
"descompactar" onde realmente pontuamos: O valor do byte de comprimento marca o final da string
ser retirado do buffer. Uma vez que esta combinação não faz sentido, exceto quando o
o código do segundo pacote não for "a*", "A*" ou "Z*", Perl não permitirá.

O código do pacote que precede "/" pode ser qualquer coisa que seja adequada para representar um número: Todos os
códigos de pacote binários numéricos e até códigos de texto como "A4" ou "Z*":

# empacota/descompacta uma string precedida por seu comprimento em ASCII
meu $buf = pack('A4/A*', "Humpty-Dumpty");
# descompacte $buf: '13 Humpty-Dumpty'
meu $txt = unpack('A4/A*', $buf);

"/" não é implementado em Perls antes de 5.6, portanto, se seu código for necessário para funcionar em
Perls, você precisará "descompactar ('Z* Z* C')" para obter o comprimento e usá-lo para criar um novo
descompacte a string. Por exemplo

# empacota uma mensagem: ASCIIZ, ASCIIZ, comprimento, string, byte
# (compatível com 5.005)
my $msg = pack( 'Z* Z* CA* C', $src, $dst, comprimento $sm, $sm, $prio);

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

Mas esse segundo "desempacotar" está correndo à frente. Ele não está usando uma string literal simples para o
modelo. Então talvez devêssemos apresentar...

Dinâmico Modelos
Até agora, vimos literais usados ​​como modelos. Se a lista de itens do pacote não tiver
comprimento fixo, uma expressão construindo o modelo é necessária (sempre que, para alguns
motivo, "()*" não pode ser usado). Aqui está um exemplo: Para armazenar valores de string nomeados de uma maneira
que pode ser convenientemente analisado por um programa C, criamos uma sequência de nomes e valores nulos
strings ASCII terminadas, com "=" entre o nome e o valor, seguido por um
byte nulo delimitador adicional. Veja como:

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

Vamos examinar as engrenagens deste moinho de bytes, um por um. Há a chamada "mapa", criando o
itens que pretendemos colocar no buffer $env: para cada chave (em $_) ele adiciona o "="
separador e o valor de entrada de hash. Cada trio é embalado com o código do modelo
seqüência "A*A*Z*" que se repete de acordo com o número de teclas. (Sim, isso é o que o
A função "keys" retorna em contexto escalar.) Para obter o último byte nulo, adicionamos um 0 em
no final da lista "pack", a ser empacotada com "C". (Os leitores atentos devem ter notado
que poderíamos ter omitido o 0.)

Para a operação inversa, teremos que determinar o número de itens no buffer
antes que possamos deixar "descompactar" rasgá-lo:

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

O "tr" conta os bytes nulos. A chamada "unpack" retorna uma lista de pares nome-valor cada
dos quais é desmontado no bloco "mapa".

Contando Repetições
Em vez de armazenar uma sentinela no final de um item de dados (ou uma lista de itens), poderíamos
preceder os dados com uma contagem. Novamente, nós empacotamos chaves e valores de um hash, precedendo cada
com uma contagem de comprimento curto sem sinal e, na frente, armazenamos o número de pares:

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

Isso simplifica a operação inversa, pois o número de repetições pode ser descompactado com
o código:

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

Observe que este é um dos raros casos em que você não pode usar o mesmo modelo para "pack"
e "unpack" porque "pack" não pode determinar uma contagem de repetição para um grupo "()".

Intel HEX
Intel HEX é um formato de arquivo para representar dados binários, principalmente para programar vários
chips, como um arquivo de texto. (Verhttp://en.wikipedia.org/wiki/.hex> para um detalhamento
descrição, ehttp://en.wikipedia.org/wiki/SREC_(file_format)> para o Motorola
formato de registro S, que pode ser desvendado usando a mesma técnica.) Cada linha começa com
dois pontos (':') e é seguido por uma sequência de caracteres hexadecimais, especificando um byte
contar n (8 bits), um endereço (16 bits, big endian), um tipo de registro (8 bits), n bytes de dados e
uma soma de verificação (8 bits) computada como o byte menos significativo da soma do complemento de dois de
os bytes anteriores. Exemplo: ":0300300002337A1E".

O primeiro passo do processamento de tal linha é a conversão, para binário, do hexadecimal
dados, para obter os quatro campos, enquanto verifica a soma de verificação. Nenhuma surpresa aqui: vamos
comece com uma simples chamada "pack" para converter tudo em binário:

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

A sequência de bytes resultante é mais conveniente para verificar a soma de verificação. Não retarde seu
programe com um loop for adicionando os valores "ord" dos bytes desta string - o "unpack"
código "%" é a coisa a ser usada para calcular a soma de 8 bits de todos os bytes, que deve ser igual
para zero:

morra a menos que descompacte( "%8C*", $binrec ) == 0;

Finalmente, vamos obter esses quatro campos. Até agora, você não deve ter nenhum problema com o
primeiros três campos - mas como podemos usar a contagem de bytes dos dados no primeiro campo como um
comprimento para o campo de dados? Aqui os códigos "x" e "X" vêm em socorro, pois permitem
pulando para frente e para trás na corda para descompactar.

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

O código "x" pula um byte, pois ainda não precisamos da contagem. O código "n" cuida do
Endereço inteiro big-endian de 16 bits e "C" descompacta o tipo de registro. Estando no deslocamento 4,
onde os dados começam, precisamos da contagem. "X4" nos traz de volta à estaca zero, que é a
byte no deslocamento 0. Agora pegamos a contagem e ampliamos para o deslocamento 4, onde estamos agora
totalmente fornecido para extrair o número exato de bytes de dados, deixando a soma de verificação final
byte sozinho.

Embalagem e Desempacotando C Estruturas


Nas seções anteriores vimos como empacotar números e cadeias de caracteres. Se isso fosse
não por alguns problemas, poderíamos concluir esta seção imediatamente com a observação concisa
que as estruturas C não contêm mais nada e, portanto, você já sabe tudo o que há
para isso. Desculpe, não: continue a ler, por favor.

Se você tem que lidar com muitas estruturas C e não quer hackear todo o seu template
strings manualmente, você provavelmente vai querer dar uma olhada no módulo CPAN
"Converter::Binário::C". Ele não apenas pode analisar sua fonte C diretamente, mas também possui
em apoio a todas as probabilidades e extremidades descritas mais adiante nesta seção.

A Alinhamento Cova
Na consideração da velocidade em relação aos requisitos de memória, a balança foi inclinada em
favor de uma execução mais rápida. Isso influenciou a maneira como os compiladores C alocam memória para
estruturas: Em arquiteturas onde um operando de 16 bits ou 32 bits pode ser movido mais rapidamente entre
lugares na memória, ou para ou de um registrador de CPU, se ele estiver alinhado em um par ou múltiplo-
de quatro ou mesmo em um endereço múltiplo de oito, um compilador C lhe dará essa velocidade
beneficiam ao colocar bytes extras em estruturas. Se você não cruzar a costa C, isso
não é provável que lhe cause qualquer aborrecimento (embora você deva se preocupar ao projetar grandes dados
estruturas, ou você quer que seu código seja portátil entre arquiteturas (você quer isso,
não é?)).

Para ver como isso afeta "pack" e "unpack", vamos comparar essas duas estruturas C:

typedef struct {
caractere c1;
calção;
caractere c2;
l longo;
} gappy_t;

typedef struct {
l longo;
calção;
caractere c1;
caractere c2;
} denso_t;

Normalmente, um compilador C aloca 12 bytes para uma variável "gappy_t", mas requer apenas 8 bytes
bytes para um "dense_t". Depois de investigar isso mais a fundo, podemos desenhar mapas de memória, mostrando
onde os 4 bytes extras estão ocultos:

0 +4 +8 +12
+--+--+--+--+--+--+--+--+--+--+--+--+
|c1|xx| s |c2|xx|xx|xx| l | xx = byte de preenchimento
+--+--+--+--+--+--+--+--+--+--+--+--+
gappy_t

0 +4 +8
+--+--+--+--+--+--+--+--+
| eu | h |c1|c2|
+--+--+--+--+--+--+--+--+
denso_t

E é aí que ocorre a primeira peculiaridade: os modelos "empacotar" e "descompactar" precisam ser preenchidos
com códigos "x" para obter esses bytes de preenchimento extras.

A pergunta natural: "Por que o Perl não pode compensar as lacunas?" justifica uma resposta. Um
boa razão é que os compiladores C podem fornecer extensões (não ANSI) permitindo todos os tipos
de controle fantasioso sobre a forma como as estruturas são alinhadas, mesmo no nível de um indivíduo
campo de estrutura. E, se isso não bastasse, existe uma coisa insidiosa chamada "união"
onde a quantidade de bytes de preenchimento não pode ser derivada do alinhamento do próximo item
sozinho.

OK, então vamos morder a bala. Aqui está uma maneira de obter o alinhamento correto inserindo
códigos de modelo "x", que não pegam um item correspondente da lista:

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

Note o "!" depois de "l": Queremos ter certeza de que empacotamos um inteiro longo conforme ele é compilado
pelo nosso compilador C. E mesmo agora, só funcionará para as plataformas onde o compilador
alinha as coisas como acima. E alguém em algum lugar tem uma plataforma onde não tem.
[Provavelmente um Cray, onde "short"s, "int"s e "long"s são todos de 8 bytes. :-)]

Contar bytes e observar alinhamentos em estruturas longas é uma tarefa chata. não é
existe uma maneira de criarmos o modelo com um programa simples? Aqui está um programa em C que faz
o truque:

#includes
#incluir

typedef struct {
caractere fc1;
f curto;
caractere fc2;
fl longo;
} gappy_t;

#define Pt(estrutura,campo,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");
}

A linha de saída pode ser usada como modelo em uma chamada "pack" ou "unpack":

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

Puxa, mais um código de modelo - como se não tivéssemos muito. Mas "@" salva nosso dia, permitindo
para especificar o deslocamento do início do buffer do pacote para o próximo item: Isso é
apenas o valor da macro "offsetof" (definida em " ") retorna quando dado um
tipo "struct" e um de seus nomes de campo ("membro-designador" em C padrão).

Nem usar deslocamentos nem adicionar "x" para preencher as lacunas é satisfatório. (Apenas imagine
o que acontece se a estrutura mudar.) O que realmente precisamos é de uma maneira de dizer "pule como
quantos bytes são necessários para o próximo múltiplo de N". Em Templatese fluente, você diz isso
com "x!N" onde N é substituído pelo valor apropriado. Aqui está a próxima versão do nosso
embalagem da estrutura:

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

Isso é certamente melhor, mas ainda temos que saber quanto tempo todos os inteiros são, e
a portabilidade está longe. Em vez de 2, por exemplo, queremos dizer "por mais longo que seja um curto
is". Mas isso pode ser feito colocando o código do pacote apropriado entre colchetes: "[s]". Portanto,
aqui está o melhor que podemos fazer:

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

Lidando com Endianismo
Agora, imagine que queremos empacotar os dados de uma máquina com uma ordem de bytes diferente.
Primeiro, teremos que descobrir o tamanho real dos tipos de dados na máquina de destino.
Vamos supor que os longos tenham 32 bits de largura e os shorts tenham 16 bits de largura. Você pode então
reescreva o modelo como:

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

Se a máquina de destino for little-endian, poderíamos escrever:

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

Isso força os membros curtos e longos a serem little-endian, e tudo bem se você
não tenha muitos membros struct. Mas também podemos usar o modificador de ordem de byte em um
grupo e escreva o seguinte:

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

Isto não é tão curto como antes, mas torna mais óbvio que pretendemos ter
ordem de bytes little-endian para um grupo inteiro, não apenas para códigos de modelo individuais. Pode
também ser mais legível e mais fácil de manter.

Alinhamento, O 2
Receio que ainda não terminamos com a captura de alinhamento. A hidra aumenta
outra cabeça feia quando você empacota arrays de estruturas:

typedef struct {
contagem curta;
glifo de caracteres;
} célula_t;

typedef cell_t buffer_t[BUFLEN];

Onde está a pegadinha? O preenchimento não é necessário antes do primeiro campo "count", nem entre
este e o próximo campo "glifo", então por que não podemos simplesmente compactar assim:

# algo dá errado aqui:
pack( 's!a' x @buffer,
map{ ( $_->{count}, $_->{glyph}) } @buffer );

Isso empacota bytes "3*@buffer", mas acontece que o tamanho de "buffer_t" é quatro vezes
"BUFLONE"! A moral da história é que o alinhamento necessário de uma estrutura ou matriz é
propagado para o próximo nível mais alto, onde temos que considerar o preenchimento at da final de cada
componente também. Assim, o modelo correto é:

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

Alinhamento, O 3
E mesmo se você levar em conta todos os itens acima, o ANSI ainda permite isso:

typedef struct {
char foo[2];
} pé;

variam em tamanho. A restrição de alinhamento da estrutura pode ser maior do que qualquer uma de suas
elementos. [E se você acha que isso não afeta nada comum, desmembre o próximo
celular que você vê. Muitos têm núcleos ARM, e as regras de estrutura ARM tornam "sizeof
(foo_t)" == 4]

Ponteiros for Como funciona o dobrador de carta de canal para Use Eles
O título desta seção indica o segundo problema que você pode encontrar mais cedo ou mais tarde
quando você empacota estruturas C. Se a função que você pretende chamar espera um, digamos, "void *"
valor vc não podes simplesmente faça uma referência a uma variável Perl. (Embora esse valor
certamente é um endereço de memória, não é o endereço onde o conteúdo da variável está
armazenado.)

O código de modelo "P" promete empacotar um "ponteiro para uma string de comprimento fixo". Não é isso que
nós queremos? Vamos tentar:

# aloca algum armazenamento e empacota um ponteiro para ele
minha $memória = "\x00" x $tamanho;
meu $memptr = pack('P', $memória);

Mas espere: "pack" não retorna apenas uma sequência de bytes? Como podemos passar essa string de
bytes para algum código C esperando um ponteiro que, afinal, nada mais é que um número? O
a resposta é simples: temos que obter o endereço numérico dos bytes retornados por "pack".

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

Obviamente, isso pressupõe que é possível fazer um typecast de um ponteiro para um unsigned long and
vice-versa, o que frequentemente funciona, mas não deve ser tomado como uma lei universal. - Agora isso
temos esse ponteiro a próxima pergunta é: Como podemos colocá-lo em bom uso? Precisamos de uma chamada
para alguma função C onde um ponteiro é esperado. O ler(2) a chamada do sistema vem à mente:

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

Depois de ler perlfunc explicando como usar "syscall", podemos escrever esta função Perl
copiando um arquivo para a saída padrão:

requer 'syscall.ph'; # execute h2ph para gerar este arquivo
subgato($){
meu $caminho = shift();
meu $tamanho = -s $caminho;
minha $memória = "\x00" x $tamanho; # aloca alguma memoria
meu $ptr = unpack('L', pack('P', $memory));
open(F, $caminho) || die( "$path: não pode abrir ($!)\n" );
meu $fd = arquivono(F);
meu $res = syscall( &SYS_read, fileno(F), $ptr, $size);
imprimir $memória;
fechar(F);
}

Este não é um espécime de simplicidade nem um modelo de portabilidade, mas ilustra
o ponto: somos capazes de nos esgueirar nos bastidores e acessar o bem guardado de Perl
memória! (Nota importante: o "syscall" do Perl não não exigem que você construa ponteiros em
esta rotatória. Você simplesmente passa uma variável string e o Perl encaminha o endereço.)

Como funciona "descompactar" com "P"? Imagine algum ponteiro no buffer prestes a ser descompactado:
Se não for o ponteiro nulo (que produzirá inteligentemente o valor "undef"), temos um
endereço inicial - mas e depois? Perl não tem como saber quanto tempo esse "comprimento fixo
string" é, portanto, cabe a você especificar o tamanho real como um comprimento explícito após "P".

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

Como consequência, "pack" ignora qualquer número ou "*" após "P".

Agora que vimos "P" em ação, podemos dar uma olhada em "p". Por que precisamos de um
segundo código de modelo para empacotar ponteiros? A resposta está por trás do simples fato
que um "unpack" com "p" promete uma string terminada em nulo começando no endereço obtido
do buffer, e isso implica em um comprimento para o item de dados a ser retornado:

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

Embora isso possa ser confuso: como consequência do comprimento ser implícito pelo
comprimento da string, um número após o código de pacote "p" é uma contagem de repetição, não um comprimento como após
"P".

Usar "pack(..., $x)" com "P" ou "p" para obter o endereço onde $x está realmente armazenado deve
ser usado com cautela. A maquinaria interna do Perl considera a relação entre um
variável e esse endereço como seu próprio assunto privado e realmente não se importa que nós
obtiveram uma cópia. Portanto:

· Não use "pack" com "p" ou "P" para obter o endereço da variável que deve ir
fora do escopo (e, assim, liberando sua memória) antes de terminar de usar o
memória nesse endereço.

· Tenha muito cuidado com as operações Perl que alteram o valor da variável. Anexando
algo para a variável, por exemplo, pode exigir realocação de seu armazenamento,
deixando você com um ponteiro para a terra de ninguém.

· Não pense que você pode obter o endereço de uma variável Perl quando ela é armazenada como
inteiro ou número duplo! "pack('P', $x)" irá forçar a variável interna
representação para string, como se você tivesse escrito algo como "$x .= ''".

É seguro, no entanto, P- ou p-pack uma string literal, porque Perl simplesmente aloca um
variável anônima.

Pack Receitas


Aqui está uma coleção de receitas enlatadas (possivelmente) úteis para "empacotar" e "descompactar":

# Converte o endereço IP para funções de socket
pack( "C4", split /\./, "123.4.5.6" );

# Contar os bits em um pedaço de memória (por exemplo, um vetor de seleção)
unpack('%32b*', $mask);

# Determine a endianidade do seu sistema
$is_little_endian = unpack( 'c', pack( 's', 1 ) );
$is_big_endian = unpack( 'xc', pack( 's', 1 ) );

# Determina o número de bits em um inteiro nativo
$bits = unpack('%32I!', ~0);

# Prepara o argumento para a chamada do sistema nanosleep
my $timespec = pack('L!L!', $secs, $nanosecs);

Para um simples despejo de memória, descompactamos alguns bytes em tantos pares de dígitos hexadecimais e
use "map" para lidar com o espaçamento tradicional - 16 bytes para uma linha:

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

Engraçados Seção


# Tirando dígitos do nada...
print unpack('C', pack('x')),
unpack('%B*', pack('A')),
unpack('H', pack('A')),
unpack( 'A', unpack( 'C', pack( 'A' ) ) ), "\n";

# Um para a estrada ;-)
my $advice = pack('tudo que você puder em uma van');

autores


Simon Cozens e Wolfgang Laun.

Use perlpacktut online usando serviços onworks.net


Servidores e estações de trabalho gratuitos

Baixar aplicativos Windows e Linux

  • 1
    Piso de escritório
    Piso de escritório
    OfficeFloor fornece inversão de
    controle de acoplamento, com sua: - dependência
    injeção - injeção de continuação -
    injeção de thread Para mais informações
    visite a...
    Baixar OfficeFloor
  • 2
    Kit Div
    Kit Div
    DivKit é um servidor de código aberto baseado em
    Estrutura de IU (SDUI). Ele permite que você
    distribuir atualizações provenientes do servidor para
    diferentes versões de aplicativos. Além disso, pode ser
    usado para ...
    Baixe o DivKit
  • 3
    subconversor
    subconversor
    Utilitário para converter entre vários
    formato de assinatura. Usuários do Shadowrocket
    deve usar ss, ssr ou v2ray como alvo.
    Você pode adicionar &remark= a
    HT curtido no Telegram...
    Baixar subconversor
  • 4
    SWASH
    SWASH
    SWASH é um numérico de uso geral
    ferramenta para simular instabilidade,
    não hidrostático, superfície livre,
    fluxo rotacional e fenômenos de transporte
    em águas costeiras como ...
    Baixar SWASH
  • 5
    VBA-M (arquivado - agora no Github)
    VBA-M (arquivado - agora no Github)
    O projeto mudou para
    https://github.com/visualboyadvance-m/visualboyadvance-m
    Recursos: Criação de truques, salvar estados multi
    sistema, suporta gba, gbc, gb, sgb,
    sgb2Tu...
    Baixar VBA-M (arquivado - agora no Github)
  • 6
    Stacer
    Stacer
    Otimizador e monitoramento de sistema Linux
    Repositório Github:
    https://github.com/oguzhaninan/Stacer.
    Público: usuários finais / desktop. Do utilizador
    interface: Qt. Programação L...
    Baixar Stacer
  • Mais "

Comandos Linux

Ad