How Perl Handles Variables

Suppose that instead of using a static variable for your bit array, you want to pass it a Perl scalar and let the program store its data there. To do so, you need to know a little about how Perl stores its data internally.

All Perl scalar variables are represented by the type SV defined in the perl.h file. The definition of this type is

struct sv {
    void*       sv_any;         /* pointer to something */ 
    U32         sv_refcnt;      /* how many references to us */ 
    U32         sv_flags;       /* what we are */ 
}; 
typedef struct sv SV;

The sv_any field points to the data held in the scalar. This can be a Perl string (called a byte array by C programmers) or a reference to a hash, array, code, scalar, or typeglob.

The sv_refcnt is a reference count used by Perl to determine when to free the variable. Finally, the sv_flags are flags used by Perl to handle variable type information and booking information.

Accessing Perl’s SV Variables

You don’t normally access the contents of an SV directly. Instead, Perl provides a rich set of functions that let you create and access SV variables.

For example, the SvIV macro turns a scalar into an integer. (If the scalar doesn’t contain an integer value, the conversion does the best it can.) For example:

void do_square(SV *value) {
            int number = SvIV(value);

If you want to set a scalar value to an integer, you can use the sv_setiv macro:

sv_setiv(value, 56);

Finally, if for some reason you need to create a scalar, there is a set of newSV... macros. For example:

unsigned char array[5] = {1, 2, 3, 4, 5}; 
new_value = newSVpv(array, 5);

The online document perldoc perlguts gives you a good introduction to the SV variable type and the functions that manipulate it. Table 14.2 contains a short list of some of the more important functions that can be used with SVs. For a complete list of all the functions you can use (all variable types), see the online document perlapi.

Table 14.2. Some Important Functions that Can Be Used with SVs.
Function Meaning
SV *result = NEWSV(count , length ) Create a new SV. Set the reference count to count and allocate length bytes. (Nothing is put in the SV,but length bytes are reserved.)
SV *result = newSViv(integer ) Create a new SV and assign it the integer value integer .
SV *result = newSVnv(float_value ) Create a new SV and assign it the floating-point value float_value.
SV *result = newSVpv(string , length ) Create a new SV and assign it the string value string . The number of bytes copied is specified by the length variable. If this variable is zero, then the length of the string is computed using the strlen function.
flag = SvIOK(SV_ptr ) Return true if the SV_ptr points to an SV that contains an integer.
integer = SvIV(SV_ptr ) Turn an SV into an integer.
double_value = SvNV(SV_ptr ) Turn an SV into a double.
string = SvPV(SV_ptr) Turn an SV into a string (char *).

Using SV

Now rewrite the bits program to let the user pass in an array. First change the function header so that it accepts a Perl scalar:

void set_bit(SV *bits, int x, int y, int value) {

The next step is to turn the SV into something you can use, namely an array and a length. This is done through the SvPV macro:

int len;    /* Length of the bit array */ 
/* The bit array */ 
unsigned char *array = SvPV(bits, len);

Now that you have the array, check to see whether it has the correct number of bytes in it. If it’s the wrong size, write out an error message and call the Perl internal function croak. (This is the equivalent of the Perl language function die.) For example:

if (len != SIZE_BYTES) {
    fprintf(stderr, "Bit array must be %d bytes long
", SIZE_BYTES); 
    croak("Can not continue"); 
}

Since SvPV is a macro, it is able to modify len and stores the length of the scalar there.

Except for a little bit of glue and some math, that is all you have to do. Listing 14.3 shows the full program.

Listing 14.3. bits2.pl
use strict; 
use warnings; 

use Inline "C"; 

sub set_bit($$$$); 
sub test_bit($$$); 

# The bit array we are using 
my $bits = pack("C*", (0) x 32); 

set_bit($bits, 1,1,1); 
set_bit($bits, 1,2,1); 
if ((test_bit($bits, 1,1) != 1) || 
    (test_bit($bits, 1,2) != 1) || 
    (test_bit($bits, 1,3) != 0)) {
    die("Test #1 Failed"); 
} 

set_bit($bits, 1,1,0); 

if (test_bit($bits, 1,1) != 0) {
    die("Test #2 Failed"); 
} 
print "Tests passed
"; 

__END__ 
__C__ 

#define X_SIZE 16 
#define Y_SIZE 16 

/* Size (in bytes) of the bit array */ 
#define SIZE_BYTES ((X_SIZE * Y_SIZE) / 8) 

/* Index into an array which is actually a string */ 
static unsigned char *element(unsigned char *data, int x, int y) 
{
    return (&data[y * (X_SIZE/8) + x]); 
} 

void set_bit(SV *bits, int x, int y, int value) {

    int len;    /* Length of the bit array */ 
    /* The bit array */ 
    unsigned char *array = SvPV(bits, len); 

    if (len != SIZE_BYTES) {
        fprintf(stderr, "Bit array must be %d bytes long
", SIZE_BYTES); 
        croak("Can not continue"); 
    } 

    if (value != 0) 
        *element(array, x/8, y) |= (0x80 >> (x % 8)); 
    else 
        *element(array, x/8, y) &= ~(0x80 >> (x % 8)); 
} 

int test_bit(SV *bits, int x, int y) 
{
    int len;    /* Length of the bit array */ 
    /* The bit array */ 
    unsigned char *array = SvPV(bits, len); 

    if (len != SIZE_BYTES) {
        fprintf(stderr, "Bit array must be %d bytes long
", SIZE_BYTES); 
        croak("Can not continue"); 
    } 

    return (
        ((*element(array, x/8, y)) & (0x80 >> (x % 8))) 
        != 0); 
}

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset