⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 perlpacktut.1

📁 视频监控网络部分的协议ddns,的模块的实现代码,请大家大胆指正.
💻 1
📖 第 1 页 / 共 4 页
字号:
C structures:.PP.Vb 6\&   typedef struct {\&     char     c1;\&     short    s;\&     char     c2;\&     long     l;\&   } gappy_t;\&\&   typedef struct {\&     long     l;\&     short    s;\&     char     c1;\&     char     c2;\&   } dense_t;.Ve.PPTypically, a C compiler allocates 12 bytes to a \f(CW\*(C`gappy_t\*(C'\fR variable, butrequires only 8 bytes for a \f(CW\*(C`dense_t\*(C'\fR. After investigating this further,we can draw memory maps, showing where the extra 4 bytes are hidden:.PP.Vb 5\&   0           +4          +8          +12\&   +\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\&   |c1|xx|  s  |c2|xx|xx|xx|     l     |    xx = fill byte\&   +\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\&   gappy_t\&\&   0           +4          +8\&   +\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\&   |     l     |  h  |c1|c2|\&   +\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\-\-+\&   dense_t.Ve.PPAnd that's where the first quirk strikes: \f(CW\*(C`pack\*(C'\fR and \f(CW\*(C`unpack\*(C'\fRtemplates have to be stuffed with \f(CW\*(C`x\*(C'\fR codes to get those extra fill bytes..PPThe natural question: \*(L"Why can't Perl compensate for the gaps?\*(R" warrantsan answer. One good reason is that C compilers might provide (non-ANSI)extensions permitting all sorts of fancy control over the way structuresare aligned, even at the level of an individual structure field. And, ifthis were not enough, there is an insidious thing called \f(CW\*(C`union\*(C'\fR wherethe amount of fill bytes cannot be derived from the alignment of the nextitem alone..PP\&\s-1OK\s0, so let's bite the bullet. Here's one way to get the alignment rightby inserting template codes \f(CW\*(C`x\*(C'\fR, which don't take a corresponding item from the list:.PP.Vb 1\&  my $gappy = pack( \*(Aqcxs cxxx l!\*(Aq, $c1, $s, $c2, $l );.Ve.PPNote the \f(CW\*(C`!\*(C'\fR after \f(CW\*(C`l\*(C'\fR: We want to make sure that we pack a longinteger as it is compiled by our C compiler. And even now, it will onlywork for the platforms where the compiler aligns things as above.And somebody somewhere has a platform where it doesn't.[Probably a Cray, where \f(CW\*(C`short\*(C'\fRs, \f(CW\*(C`int\*(C'\fRs and \f(CW\*(C`long\*(C'\fRs are all 8 bytes. :\-)].PPCounting bytes and watching alignments in lengthy structures is bound to be a drag. Isn't there a way we can create the template with a simpleprogram? Here's a C program that does the trick:.PP.Vb 2\&   #include <stdio.h>\&   #include <stddef.h>\&\&   typedef struct {\&     char     fc1;\&     short    fs;\&     char     fc2;\&     long     fl;\&   } gappy_t;\&\&   #define Pt(struct,field,tchar) \e\&     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( "\en" );\&   }.Ve.PPThe output line can be used as a template in a \f(CW\*(C`pack\*(C'\fR or \f(CW\*(C`unpack\*(C'\fR call:.PP.Vb 1\&  my $gappy = pack( \*(Aq@0c @2s! @4c @8l!\*(Aq, $c1, $s, $c2, $l );.Ve.PPGee, yet another template code \- as if we hadn't plenty. But \&\f(CW\*(C`@\*(C'\fR saves our day by enabling us to specify the offset from the beginningof the pack buffer to the next item: This is just the valuethe \f(CW\*(C`offsetof\*(C'\fR macro (defined in \f(CW\*(C`<stddef.h>\*(C'\fR) returns whengiven a \f(CW\*(C`struct\*(C'\fR type and one of its field names (\*(L"member-designator\*(R" in C standardese)..PPNeither using offsets nor adding \f(CW\*(C`x\*(C'\fR's to bridge the gaps is satisfactory.(Just imagine what happens if the structure changes.) What we really needis a way of saying \*(L"skip as many bytes as required to the next multiple of N\*(R".In fluent Templatese, you say this with \f(CW\*(C`x!N\*(C'\fR where N is replaced by theappropriate value. Here's the next version of our struct packaging:.PP.Vb 1\&  my $gappy = pack( \*(Aqc x!2 s c x!4 l!\*(Aq, $c1, $s, $c2, $l );.Ve.PPThat's certainly better, but we still have to know how long all theintegers are, and portability is far away. Rather than \f(CW2\fR,for instance, we want to say \*(L"however long a short is\*(R". But this can bedone by enclosing the appropriate pack code in brackets: \f(CW\*(C`[s]\*(C'\fR. So, here'sthe very best we can do:.PP.Vb 1\&  my $gappy = pack( \*(Aqc x![s] s c x![l!] l!\*(Aq, $c1, $s, $c2, $l );.Ve.Sh "Dealing with Endian-ness".IX Subsection "Dealing with Endian-ness"Now, imagine that we want to pack the data for a machine with adifferent byte-order. First, we'll have to figure out how big the datatypes on the target machine really are. Let's assume that the longs are32 bits wide and the shorts are 16 bits wide. You can then rewrite thetemplate as:.PP.Vb 1\&  my $gappy = pack( \*(Aqc x![s] s c x![l] l\*(Aq, $c1, $s, $c2, $l );.Ve.PPIf the target machine is little-endian, we could write:.PP.Vb 1\&  my $gappy = pack( \*(Aqc x![s] s< c x![l] l<\*(Aq, $c1, $s, $c2, $l );.Ve.PPThis forces the short and the long members to be little-endian, and isjust fine if you don't have too many struct members. But we could alsouse the byte-order modifier on a group and write the following:.PP.Vb 1\&  my $gappy = pack( \*(Aq( c x![s] s c x![l] l )<\*(Aq, $c1, $s, $c2, $l );.Ve.PPThis is not as short as before, but it makes it more obvious that weintend to have little-endian byte-order for a whole group, not onlyfor individual template codes. It can also be more readable and easierto maintain..Sh "Alignment, Take 2".IX Subsection "Alignment, Take 2"I'm afraid that we're not quite through with the alignment catch yet. Thehydra raises another ugly head when you pack arrays of structures:.PP.Vb 4\&   typedef struct {\&     short    count;\&     char     glyph;\&   } cell_t;\&\&   typedef cell_t buffer_t[BUFLEN];.Ve.PPWhere's the catch? Padding is neither required before the first field \f(CW\*(C`count\*(C'\fR,nor between this and the next field \f(CW\*(C`glyph\*(C'\fR, so why can't we simply packlike this:.PP.Vb 3\&   # something goes wrong here:\&   pack( \*(Aqs!a\*(Aq x @buffer,\&         map{ ( $_\->{count}, $_\->{glyph} ) } @buffer );.Ve.PPThis packs \f(CW\*(C`3*@buffer\*(C'\fR bytes, but it turns out that the size of \&\f(CW\*(C`buffer_t\*(C'\fR is four times \f(CW\*(C`BUFLEN\*(C'\fR! The moral of the story is thatthe required alignment of a structure or array is propagated to thenext higher level where we have to consider padding \fIat the end\fRof each component as well. Thus the correct template is:.PP.Vb 2\&   pack( \*(Aqs!ax\*(Aq x @buffer,\&         map{ ( $_\->{count}, $_\->{glyph} ) } @buffer );.Ve.Sh "Alignment, Take 3".IX Subsection "Alignment, Take 3"And even if you take all the above into account, \s-1ANSI\s0 still lets this:.PP.Vb 3\&   typedef struct {\&     char     foo[2];\&   } foo_t;.Ve.PPvary in size. The alignment constraint of the structure can be greater thanany of its elements. [And if you think that this doesn't affect anythingcommon, dismember the next cellphone that you see. Many have \s-1ARM\s0 cores, andthe \s-1ARM\s0 structure rules make \f(CW\*(C`sizeof (foo_t)\*(C'\fR == 4].Sh "Pointers for How to Use Them".IX Subsection "Pointers for How to Use Them"The title of this section indicates the second problem you may run intosooner or later when you pack C structures. If the function you intendto call expects a, say, \f(CW\*(C`void *\*(C'\fR value, you \fIcannot\fR simply takea reference to a Perl variable. (Although that value certainly is amemory address, it's not the address where the variable's contents arestored.).PPTemplate code \f(CW\*(C`P\*(C'\fR promises to pack a \*(L"pointer to a fixed length string\*(R".Isn't this what we want? Let's try:.PP.Vb 3\&    # allocate some storage and pack a pointer to it\&    my $memory = "\ex00" x $size;\&    my $memptr = pack( \*(AqP\*(Aq, $memory );.Ve.PPBut wait: doesn't \f(CW\*(C`pack\*(C'\fR just return a sequence of bytes? How can we pass thisstring of bytes to some C code expecting a pointer which is, after all,nothing but a number? The answer is simple: We have to obtain the numericaddress from the bytes returned by \f(CW\*(C`pack\*(C'\fR..PP.Vb 1\&    my $ptr = unpack( \*(AqL!\*(Aq, $memptr );.Ve.PPObviously this assumes that it is possible to typecast a pointerto an unsigned long and vice versa, which frequently works but should notbe taken as a universal law. \- Now that we have this pointer the next questionis: How can we put it to good use? We need a call to some C functionwhere a pointer is expected. The \fIread\fR\|(2) system call comes to mind:.PP.Vb 1\&    ssize_t read(int fd, void *buf, size_t count);.Ve.PPAfter reading perlfunc explaining how to use \f(CW\*(C`syscall\*(C'\fR we can writethis Perl function copying a file to standard output:.PP.Vb 12\&    require \*(Aqsyscall.ph\*(Aq;\&    sub cat($){\&        my $path = shift();\&        my $size = \-s $path;\&        my $memory = "\ex00" x $size;  # allocate some memory\&        my $ptr = unpack( \*(AqL\*(Aq, pack( \*(AqP\*(Aq, $memory ) );\&        open( F, $path ) || die( "$path: cannot open ($!)\en" );\&        my $fd = fileno(F);\&        my $res = syscall( &SYS_read, fileno(F), $ptr, $size );\&        print $memory;\&        close( F );\&    }.Ve.PPThis is neither a specimen of simplicity nor a paragon of portability butit illustrates the point: We are able to sneak behind the scenes andaccess Perl's otherwise well-guarded memory! (Important note: Perl's\&\f(CW\*(C`syscall\*(C'\fR does \fInot\fR require you to construct pointers in this roundaboutway. You simply pass a string variable, and Perl forwards the address.).PPHow does \f(CW\*(C`unpack\*(C'\fR with \f(CW\*(C`P\*(C'\fR work? Imagine some pointer in the bufferabout to be unpacked: If it isn't the null pointer (which will smartlyproduce the \f(CW\*(C`undef\*(C'\fR value) we have a start address \- but then what?Perl has no way of knowing how long this \*(L"fixed length string\*(R" is, soit's up to you to specify the actual size as an explicit length after \f(CW\*(C`P\*(C'\fR..PP.Vb 2\&   my $mem = "abcdefghijklmn";\&   print unpack( \*(AqP5\*(Aq, pack( \*(AqP\*(Aq, $mem ) ); # prints "abcde".Ve.PPAs a consequence, \f(CW\*(C`pack\*(C'\fR ignores any number or \f(CW\*(C`*\*(C'\fR after \f(CW\*(C`P\*(C'\fR..PPNow that we have seen \f(CW\*(C`P\*(C'\fR at work, we might as well give \f(CW\*(C`p\*(C'\fR a whirl.Why do we need a second template code for packing pointers at all? The answer lies behind the simple fact that an \f(CW\*(C`unpack\*(C'\fR with \f(CW\*(C`p\*(C'\fR promisesa null-terminated string starting at the address taken from the buffer,and that implies a length for the data item to be returned:.PP.Vb 2\&   my $buf = pack( \*(Aqp\*(Aq, "abc\ex00efhijklmn" );\&   print unpack( \*(Aqp\*(Aq, $buf );    # prints "abc".Ve.PPAlbeit this is apt to be confusing: As a consequence of the length beingimplied by the string's length, a number after pack code \f(CW\*(C`p\*(C'\fR is a repeatcount, not a length as after \f(CW\*(C`P\*(C'\fR..PPUsing \f(CW\*(C`pack(..., $x)\*(C'\fR with \f(CW\*(C`P\*(C'\fR or \f(CW\*(C`p\*(C'\fR to get the address where \f(CW$x\fR isactually stored must be used with circumspection. Perl's internal machineryconsiders the relation between a variable and that address as its very own private matter and doesn't really care that we have obtained a copy. Therefore:.IP "\(bu" 4Do not use \f(CW\*(C`pack\*(C'\fR with \f(CW\*(C`p\*(C'\fR or \f(CW\*(C`P\*(C'\fR to obtain the address of variablethat's bound to go out of scope (and thereby freeing its memory) before youare done with using the memory at that address..IP "\(bu" 4Be very careful with Perl operations that change the value of thevariable. Appending something to the variable, for instance, might requirereallocation of its storage, leaving you with a pointer into no-man's land..IP "\(bu" 4Don't think that you can get the address of a Perl variablewhen it is stored as an integer or double number! \f(CW\*(C`pack(\*(AqP\*(Aq, $x)\*(C'\fR willforce the variable's internal representation to string, just as if youhad written something like \f(CW\*(C`$x .= \*(Aq\*(Aq\*(C'\fR..PPIt's safe, however, to P\- or p\-pack a string literal, because Perl simplyallocates an anonymous variable..SH "Pack Recipes".IX Header "Pack Recipes"Here are a collection of (possibly) useful canned recipes for \f(CW\*(C`pack\*(C'\fRand \f(CW\*(C`unpack\*(C'\fR:.PP.Vb 2\&    # Convert IP address for socket functions\&    pack( "C4", split /\e./, "123.4.5.6" ); \&\&    # Count the bits in a chunk of memory (e.g. a select vector)\&    unpack( \*(Aq%32b*\*(Aq, $mask );\&\&    # Determine the endianness of your system\&    $is_little_endian = unpack( \*(Aqc\*(Aq, pack( \*(Aqs\*(Aq, 1 ) );\&    $is_big_endian = unpack( \*(Aqxc\*(Aq, pack( \*(Aqs\*(Aq, 1 ) );\&\&    # Determine the number of bits in a native integer\&    $bits = unpack( \*(Aq%32I!\*(Aq, ~0 );\&\&    # Prepare argument for the nanosleep system call\&    my $timespec = pack( \*(AqL!L!\*(Aq, $secs, $nanosecs );.Ve.PPFor a simple memory dump we unpack some bytes into just as many pairs of hex digits, and use \f(CW\*(C`map\*(C'\fR to handle the traditionalspacing \- 16 bytes to a line:.PP.Vb 4\&    my $i;\&    print map( ++$i % 16 ? "$_ " : "$_\en",\&               unpack( \*(AqH2\*(Aq x length( $mem ), $mem ) ),\&          length( $mem ) % 16 ? "\en" : \*(Aq\*(Aq;.Ve.SH "Funnies Section".IX Header "Funnies Section".Vb 5\&    # Pulling digits out of nowhere...\&    print unpack( \*(AqC\*(Aq, pack( \*(Aqx\*(Aq ) ),\&          unpack( \*(Aq%B*\*(Aq, pack( \*(AqA\*(Aq ) ),\&          unpack( \*(AqH\*(Aq, pack( \*(AqA\*(Aq ) ),\&          unpack( \*(AqA\*(Aq, unpack( \*(AqC\*(Aq, pack( \*(AqA\*(Aq ) ) ), "\en";\&\&    # One for the road ;\-)\&    my $advice = pack( \*(Aqall u can in a van\*(Aq );.Ve.SH "Authors".IX Header "Authors"Simon Cozens and Wolfgang Laun.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -