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

";

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

";

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

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

";

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