C::Blocks Advent Day 4

This is the C::Blocks Advent Calendar, in which I release a new treat each day about the C::Blocks library. Yesterday I showed how to get information across the boundary between Perl and C with minimal boiler plate. Today I explain how to declare and use C functions. I also explain the killer feature of C::Blocks: declaring C functions and other things within a module that can be `use`d throughout your code.

I will begin with a specific implementation of a random number generator. This is a decent candidate for a C::Blocks implementation when you anticipate needing to produce many random numbers, such as for Monte Carlo simulations. I came across a nice little writeup about random number generators by David Jones, and the author provides a decent starting point called `KISS`. How would that library be implemented using C::Blocks? Place the global variables and the function in a `clex` block, then call the function in your `cblock`s, like so:

``````use strict;
use warnings;
use C::Blocks;

# Implement KISS random number generator, copy-and-pasted from
# http://www0.cs.ucl.ac.uk/staff/d.jones/GoodPracticeRNG.pdf
clex {
/* Note: y must never be set to zero;
* z and c must not be simultaneously zero */
static unsigned int x = 123456789,y = 362436000,
z = 521288629,c = 7654321; /* State variables */

unsigned int KISS() {
unsigned long long t, a = 698769069ULL;
x = 69069*x+12345;
y ^= (y<<13); y ^= (y>>17); y ^= (y<<5);
t = a*z+c; c = (t>>32);
return x+y+(z=t);
}
}

use C::Blocks::Types qw(uint);

# Get a random number from the generator
my uint \$random = 0;
cblock { \$random = KISS(); }
print "Random number is \$random\n";
``````

When run, this produces

``````\$ perl test.pl
Random number is 2079675107
``````

As you can see, the `clex` block contains a function and some global variable declarations which are available to the function and to any `cblock`s later in the same lexical scope. Indeed, as the name suggests, the visibility of the declarations in `clex` blocks are lexically scoped. As you know, you cannot use a Perl variable outside of its lexical scope. Likewise, the Perl block that surrounds a `clex` block defines the scope of the declarations in that block: a `cblock` or `clex` block outside of that scope will not be able to see the declarations.

David Jones makes a number of suggestions for improving the generator, but the aim of this Advent treat is not really to implement a random number generator. I simply want to use the idea of such a generator to motivate some of the features of C::Blocks.

A random number generator is meant to be reused. I could of course create a Perl function with the `cblock` in it, making it reusable from Perl. But how do I make my C functions sharable to other modules and scripts? The answer is simple. Place the `clex` block in a module with a package name matching the module name, and change `clex` to `cshare`. For example, here is a module that provides the same random number generator, called `MyRNG.pm`:

``````# MyRNG.pm
package MyRNG;
use strict;
use warnings;
use C::Blocks;
use C::Blocks::Types qw(uint);

# Implement KISS random number generator, copy-and-pasted from
# http://www0.cs.ucl.ac.uk/staff/d.jones/GoodPracticeRNG.pdf
cshare {
unsigned int x, y, z, c;

unsigned int KISS() {
unsigned long long t, a = 698769069ULL;
x = 69069*x+12345;
y ^= (y<<13); y ^= (y>>17); y ^= (y<<5);
t = a*z+c; c = (t>>32);
return x+y+(z=t);
}
}

# Set up state
my uint (\$x, \$y, \$z, \$c) = map 1 + int(rand(4294967294)), 1 .. 4;
cblock {
x = \$x;
y = \$y;
z = \$z;
c = \$c;
}
1;
``````

Notice that this module initializes the state to random numbers via a `cblock`. For `cblock`s written within the module itself, there is no difference between `clex` and `cshare`. The difference comes in which blocks have their symbol tables shared when the module is `use`d. Here I illustrate that I can use a local `cblock` to initialize global variables declared in a `cshare` block.

An example of a script that uses this module:

``````use strict;
use warnings;
use C::Blocks;
use C::Blocks::Types qw(uint);

use MyRNG; # import KISS()

# Produce a random number
my uint \$rand = 0;
cblock {
\$rand = KISS();
}

print "Random number is \$rand\n";
``````

Take a moment to appreciate the following two facts: (1) Writing the module was absurdly easy, basically copying a `clex` block into a module file and renaming the block to `cshare`. (2) Importing and using the function in the module was absurdly easy, just a `use` statement. Inline::C has made the first of these fairly simple, and ExtUtils::Depends sorta provides a system for the second of these. C::Blocks was designed to simultaneously solve both, and I believe it provides an easier-to-use approach.

Finally, here is an illustration of the lexical scoping in action, to give you an illustration of how it really works. The symbol tables imported when you `use` a module are lexically scoped to the block into which you `use` them (just like the effect of `use warnings` is lexically scoped).

``````use strict;
use warnings;
use C::Blocks;
use C::Blocks::Types qw(uint);

my uint \$rand = 0;

# Create an inner lexical scope
{
use MyRNG;
cblock {
\$rand = KISS();
}
print "First random number is \$rand\n";
}

cblock {
\$rand = KISS();
}
print "Second random number is \$rand\n";
``````

Upon running this script, I got an error:

``````\$ perl test.pl
C::Blocks compiler error:
test.pl:18: error: undeclared function 'KISS'
``````

If you comment out that line, it runs just fine.

Today I explained how C::Blocks makes it easy to write functions and other declarations using `clex` blocks. I also explained how to write a module that provides function and other declarations for other modules by using `cshare` blocks. This module-based C code sharing was the driving impetus for this project all along, and getting it right has been central to my work on it. Even though C::Blocks makes all of this easy, does that mean you should use it? Perl is much more expressive and you may be able to articulate your algorithmic thoughts in 1/3 the number of lines compared to a C implementation. Choosing the right tool---the right language---for the job shall be the topic of a forthcoming treat.

C::Blocks Advent Day 1 2 3 4 5 6 7 8 9 10 11 12 13

very cool!