2010-10-04 14 views
11

In Perl, pack e unpack hanno due modelli per convertire i byte da/esagono:Quando userete decomprimere ('h *' ...) o pack ('h *' ...)?

h       Una stringa esadecimale (basso nybble prima).
H       Una stringa esadecimale (nybble alto per primo).

Questo è meglio chiarito con un esempio:

use 5.010; # so I can use say 
my $buf = "\x12\x34\x56\x78"; 

say unpack('H*', $buf); # prints 12345678 
say unpack('h*', $buf); # prints 21436587 

Come si può vedere, H è quello che la gente in generale intende quando pensano di conversione byte da/esadecimale. Quindi qual è lo scopo di h? Larry deve aver pensato che qualcuno potrebbe usarlo, o non si sarebbe preso la briga di includerlo.

Puoi fare un esempio del mondo reale in cui ci si vuole realmente utilizzare h invece di H con pack o unpack? Sto cercando un esempio specifico; se sei a conoscenza di una macchina che organizza i suoi byte in quel modo, cos'era e puoi collegarti ad alcuni documenti su di essa?

posso pensare di esempi in cui si poteva usoh, come ad esempio la serializzazione di alcuni dati, quando non si interessa davvero quello che il formato è, fino a quando si può leggere di nuovo, ma H sarebbe altrettanto utile per quello. Sto cercando un esempio in cui h è più utile di H.

risposta

9

Ricordare nei giorni brutti di MS-DOS che alcune funzioni del sistema operativo erano controllate impostando nibble alti e bassi nibbles su un registro ed eseguendo un'intervallo xx. Ad esempio, Int 21 ha avuto accesso a molte funzioni di file. Dovresti impostare il nibble alto come numero di unità - chi avrà più di 15 unità? Il basso nibble come funzione richiesta su tale unità, ecc.

Here è un vecchio codice CPAN che utilizza il pacchetto come descritto per impostare i registri per eseguire una chiamata di sistema MS-DOS.

Blech !!! Non mi manca di MS-DOS a tutti ...

--edit

Qui è specifico codice sorgente: Scarica Perl 5,00,402 mila per DOS HERE, decomprimere,

Nel file di Opcode.pm e Opcode .pl si vede l'uso di unpack("h*",$_[0]); qui:

sub opset_to_hex ($) { 
    return "(invalid opset)" unless verify_opset($_[0]); 
    unpack("h*",$_[0]); 
} 

non ho seguito il codice tutto il percorso attraverso, ma il mio sospetto è questo è quello di recuperare informazioni da una chiamata di sistema MS-DOS ...

diversi interi negozi CPU e numeri in virgola mobile in diverse ordini (chiamati endianness) e larghezze (3: in perlport per Perl 5,8-8, ci sono queste prove per endianess del target suggerito 2-bit e 64-bit sono gli più comuni oggi). Ciò influisce sui programmi quando tentano di trasferire i numeri in formato binario da un'architettura CPU a un'altra, in genere "live" tramite connessione di rete o memorizzando i numeri nella memoria secondaria come un file disco o nastro.

Gli ordini di stoccaggio in conflitto fanno completamente casino dai numeri. Se un ospite little-endian (Intel, VAX) negozi 0x12345678 (305419896 in decimale), un big-endian host (Motorola, Sparc, PA) legge come 0x78563412 (2018915346 in decimale). Alpha e MIPS possono essere: Digital/Compaq utilizzato/li usa in modalità little-endian; SGI/Cray utilizza in modalità big-endian. Per evitare questo problema nelle connessioni di rete (socket) utilizzare i formati pack e unpackn e N, gli ordini di "rete" . Questi sono garantiti per essere portatili.

A partire dal Perl 5.8.5, è anche possibile utilizzare i > e < modificatori per forzare l'ordine dei byte big-o little-endian. Ciò è utile se si desidera che memorizzi interi con segno o interi a 64 bit, ad esempio.

È possibile esplorare l'endianness della piattaforma per l'estrazione, una struttura di dati confezionato in formato nativo quali:

print unpack("h*", pack("s2", 1, 2)), "\n"; 
    # '10002000' on e.g. Intel x86 or Alpha 21064 in little-endian mode 
    # '00100020' on e.g. Motorola 68040 

Se è necessario distinguere tra le architetture endian si potrebbe usare uno dei variabili impostate come così:

$is_big_endian = unpack("h*", pack("s", 1)) =~ /01/; 
    $is_little_endian = unpack("h*", pack("s", 1)) =~ /^1/; 

diverse larghezze possono causare il troncamento anche tra le piattaforme di uguale endianness. La piattaforma di larghezza ridotta perde le parti superiori del numero . Non esiste una buona soluzione per questo problema se non per evitare che trasferisca o memorizzi numeri binari non elaborati.

Uno può circumnavigare entrambi questi problemi in due modi. Sia trasferimento e memorizzare numeri sempre in formato testo, invece di greggio binario, oppure considerare l'utilizzo di moduli come Data::Dumper (inclusi nel distribuzione standard di Perl 5.005) e Storable (incluso come di Perl 5.8). Mantenere tutti i dati come testo semplifica notevolmente gli argomenti.

I v-string sono portatili solo fino al v2147483647 (0x7FFFFFFF), che è quanto lontano EBCDIC, o più precisamente UTF-EBCDIC andrà.

Sembra che unpack("h*",...) viene utilizzato più spesso di quanto pack("h*",...). Ho fatto notare che return qq'unpack("F", pack("h*", "$hex"))'; viene utilizzato in Deparse.pm e IO-Compress utilizza pack("*h",...) in Perl 5.12

Se volete altri esempi, ecco un Google Code Search list. È possibile vedere che pack|unpack("h*"...) è piuttosto raro e per lo più riguarda la determinazione della endianità della piattaforma ...

+0

Questo codice usa' pack', ma non usa 'h' o' H' con esso, solo 's' e' c'. – cjm

3

Immagino sia utile quando si trasferiscono dati o si leggono dati da una macchina con caratteristiche diverse. Se alcuni processi prevedono di ricevere dati nel modo in cui normalmente lo rappresentano in memoria, è meglio inviare i dati in questo modo.

+0

Non credo che entri l'endianità, perché questo è nybbles _within_ un byte. I byte sono ancora elaborati nello stesso ordine. – cjm

+4

anche il mixed o il middle-endianess esistono. – rafl

+0

Puoi dare un esempio specifico di una macchina del genere? – cjm

0

La distinzione tra i due ha a che fare solo con i dati big-endian o little-endian. A volte non hai alcun controllo sulla fonte o sulla destinazione dei tuoi dati, quindi i flag H e h sono disponibili per darti l'opzione. V e N ci sono per lo stesso motivo.

+1

Non credo che entri l'endianess, perché questo è nybbles _within_ un byte. I byte sono ancora elaborati nello stesso ordine. – cjm

+2

come menzionato da 'rafl', questi sono lì per i casi in cui si hanno a che fare con dati" divertenti ", pensano sistemi legacy e formati di file binari esoterici scarsamente documentati –