"Sputnik" help  
Sputnik Help
Language Reference - Preprocessor - Function-like Macros

Function-like Macros

You can also define macros whose use looks like a function call. These are called functionlike macros. To define a function-like macro, you use the same ‘#define’ directive, but you put a pair of parentheses immediately after the macro name. For example,

#define INIT() say("init done");
INIT();
// PRINTS
// init done

A function-like macro is only expanded if its name appears with a pair of parentheses after it. If you write just the name, it is left alone. This can be useful when you have a function and a macro of the same name, and you wish to use the function sometimes

Function foo($a) // regular function
{
    return $a + 2;
}
#define FOO(x) (x + 1)  /* optimized inline version */
say foo(5);
say FOO(5);
// PRINTS
// 7
// 6

Here the call to (capital) FOO() will use the macro, but the non capital (ie the non-macro one) will use the real function.

If you do not include the parentheses in a function-like macro it will produce an error like so

#define FOO(x) (x + 1)
say FOO;
// -- many errors ---

If you put spaces between the macro name and the parentheses in the macro definition, that does not define a function-like macro, it defines an object-like macro whose expansion happens to begin with a pair of parentheses.

#define INIT ()    say("init done");
INIT();
// BECOMES
// () say("init done");();

The first two pairs of parentheses in this expansion come from the macro. The third is the pair that was originally after the macro invocation. Since INIT is an object-like macro, it does not consume those parentheses.

Here is a fairly complex example of using a function-like macro to aid in generation of random numbers:

// Constant representing the maximum value for the RANDU algorithm
#define RANDU_MAX 32767
// Macro for generating a random number in the range [min, max] using the RANDU algorithm
#define RanduRange(min, max) ((min) + Randu() % ((max) - (min) + 1))

// Function to generate pseudo-random numbers using the RANDU algorithm
Function Randu($seed = null)
{
    // Static variable to store the current state of the generator
    static $ctx = 777;
    // If a seed is provided, initialize the generator with the seed and return true
    if ($seed !== null)
    {
        $ctx = $seed;
        return true;
    }
    // Calculate the next state of the generator using the RANDU algorithm
    my $hi = $ctx / 127773;
    my $lo = $ctx % 127773;
    my $x = 16807 * $lo - 2836 * $hi;
    // Handle the case where $x is negative
    if ($x < 0)
        $x += 0x7fffffff;
    // Update the generator state and get the result
    $result = ((*$ctx) = $x);
    // Ensure the result is non-negative
    if ($result < 0)
        $result = abs($result);
    // Return the result within the range [0, RANDU_MAX]
    return $result % ((long)RANDU_MAX + 1);
}

// Main section
say "Main";
// Loop to print 10 random numbers and their corresponding ranges
my $count = 10;
while ($count--)
    say Randu() . " -> " . RanduRange(10, 50);

// Final section
say "Final";
// Set the seed to 1337 and print a random number and its range
Randu(1337);
say Randu() . " -> " . RanduRange(10, 50);
// Set the seed to 1337 again and print another random number and its range
Randu(1337);
say Randu() . " -> " . RanduRange(10, 50);

// PRINTS
// Main
// 17375 -> 13
// 8428 -> 41
// 31535 -> 32
// 3516 -> 47
// 29802 -> 22
// 9857 -> 13
// 19825 -> 49
// 4980 -> 18
// 18648 -> 14
// 10625 -> 45
// Final
// 24879 -> 46
// 24879 -> 46

As you can see, we utilized the RanduRange macro to facilitate the generation of random values within a specified range. The RanduRange macro, defined through the #define preprocessor directive, acts as a function-like construct, allowing us to easily obtain random integers between the given 'min' and 'max' values.


Contact
Cheryl (uberfox@hotmail.com)
Homepage
http://ubersoft.org