|
The CnetInt64 datatype
As of v2.0, cnet supports a 64-bit integer datatype
named CnetInt64 which is used to store all times (now in microseconds)
and large statistics.
The datatype and a number of arithmetic,
conversion, and I/O routines are defined in the
<cnet64bits.h> header file which,
like the <cnet.h> header file (and included by it),
is located via the value of CNETPATH.
Some modern C compilers support 64-bit integers directly (in a variety of ways)
and others don't. cnet attempts to hide the differences with
the CnetInt64 datatype.
cnet uses the CnetInt64 datatype extensively itself
(internally) and defines the node and link attributes of
nodeinfo.messagerate,
nodeinfo.time_in_usec, and
linkinfo[i].propagationdelay
to be of type CnetInt64.
The second parameter to the CNET_start_timer() function
is also of type CnetInt64.
Invoke the cnet simulator without any arguments.
If your C compiler provides native
support for the CnetInt64 datatype, then you can use the 64-bit
integers as you would any others - in assignments,
in arithmetic expressions, in Boolean comparisons, and in (most) I/O statements.
prompt> cnet
.....
The cnet header file is /usr/local/cnetlib/cnet.h.
Protocols will be compiled with /usr/bin/gcc.
Your compiler provides native support for the CnetInt64 type.
Protocols will be linked with /usr/bin/gcc.
|
|
However, if your compiler does not provide such native support,
or if you wish to write portable protocol codes to be used on machines
with and without CnetInt64 support, then you'll need to be a
bit more ``long-winded'' when dealing with the 64-bit integers.
Functions supporting the CnetInt64 datatype
Without native compiler support,
cnet supports the 64-bit integers using a C structure of two
32-bit integers, and many supporting functions.
You do not need to manipulate this structure directly;
instead you should use the following functions to assign, convert,
and compare values of the CnetInt64 datatype.
To provide maximum portability,
cnet is itself written using these exact same functions.
If your compiler does provide native support for the
CnetInt64 datatype,
you can still use these functions in your protocols
with virtually no loss of performance, albeit with some loss of readability.
A number of other, far less common, CnetInt64 functions
are also available in the <cnet64bits.h> header file.
- Declarations, initialization, and constants
- Variables of type CnetInt64 may be declared and defined in
the same locations as all other variables,
as fields in structures,
passed as parameters to functions, and returned as function results.
However, as members of structures,
they cannot be (consistently) initialized at compile-time,
and so it is best to initialize them at run-time.
CnetInt64 result; declares a 64-bit integer variable
int64_INIT(hi, lo) a constant specifying its 2x32-bit halves
int64_ZERO provides the 64-bit value for zero
int64_ONE provides the 64-bit value for one
int64_MAXINT provides the largest possible 64-bit integer
int64_MININT provides the smallest possible 64-bit integer
|
|
- Type conversions
- Each of these type conversions is called first with the variable in
which the result will be placed, and then the expression (or variable)
from which the initial value should be taken.
The first example of these,
pronouced ``int-to-long'' (32-bit integer to 64-bit integer),
is frequently used to initialize a CnetInt64 variable with
a small constant value.
When converting from a longer to a shorter type,
there may be the inevitable loss of accuracy or precision.
int64_I2L(l, i) assigns ((l) = (CnetInt64)(i))
int64_L2I(i, l) assigns ((i) = (CnetInt32)(l))
int64_L2F(f, l) assigns ((f) = (CnetFloat64)(l))
int64_F2L(l, f) assigns ((l) = (CnetInt64)(f))
|
|
- Arithmetic
- Arithmetic must be performed as if we were dealing with a 3-register
assembly language.
Each function takes the variable of its eventual 64-bit result as its first
parameter, and one or two other 64-bit integers.
It is permissible for any or all of the parameters to be the same variable.
int64_NEG(r, a) performs ((r) = -(a))
int64_ADD(r, a, b) performs ((r) = (a) + (b))
int64_SUB(r, a, b) performs ((r) = (a) - (b))
int64_MUL(r, a, b) performs ((r) = (a) * (b))
int64_DIV(r, a, b) performs ((r) = (a) / (b))
int64_MOD(r, a, b) performs ((r) = (a) % (b))
|
|
- Comparison
- The following Boolean predicates each take one or two CnetInt64
values and return the result of the indicated comparison.
int64_IS_ZERO(a) tests ((a) == 0)
int64_EQ(a, b) tests ((a) == (b))
int64_NE(a, b) tests ((a) != (b))
int64_GE_ZERO(a) tests ((a) >= 0)
int64_CMP(a, op, b) tests ((CnetInt64)(a) op (CnetInt64)(b))
|
|
The last one is a little tricky, as any of the 6 relational operators
may be provided as the second parameter,
for example if(int64_CMP(a, >, b)) ...
- Input and output
- Without compiler support for the CnetInt64 datatype,
we cannot simply pass it to functions such as printf().
Instead, we use two conversion functions to convert a CnetInt64
value either to or from a character array (a string),
and then deal with the character array instead,
probably with %s.
A note of caution that int64_L2A(),
pronounced ``long-to-alpha'',
formats the 64-bit integer into an internal static character array.
A copy of this array should be taken,
with strdup(), if necessary.
int64_A2L(string) converts the string, returning a 64-bit int.
int64_L2A(value, commas) formats the indicated value, returning the
address of the array holding the character
representation. The Boolean commas requests
that commas be included every third digit.
|
|
|