.\" @STR
.\" @GLUE
.\" @STATIC_ASSERT
-.\" COMMA
+.\" @CHECK_TYPE
+.\" @CONVERT_CAREFULLY
+.\" @UNCONST
+.\" @UNVOLATILE
+.\" @UNQUALIFY
+.\" @COMMA
.
.\" @ISALNUM
.\" @ISALPHA
.nf
.B "#include <mLib/macros.h>"
.PP
-.BI "size_t N(" array ");"
+.BI "size_t N(" type " " array "[]);"
.BI "STR(" tokens\fR... ")"
.BI "GLUE(" tokens\fR... ", " tokens\fR... ")"
.BI "STATIC_ASSERT(" cond ", " msg ");"
+.BI "int CHECK_TYPE(" expty ", " expty " " x );
+.IB newty " CONVERT_CAREFULLY(" newty ", " expty ", " expty " " x );
+.IB type " *UNCONST(" type ", const " type " *" p );
+.IB type " *UNVOLATILE(" type ", volatile " type " *" p );
+.IB type " *UNQUALIFY(" type ", const volatile " type " *" p );
+.B "#define COMMA ,"
.PP
.BI "ISALNUM(int " ch ");"
.BI "ISALPHA(int " ch ");"
.IR msg .
.PP
The
+.B CHECK_TYPE
+macro checks at compile-time that
+.I x
+has (or, at least, is assignment-compatible with) type
+.IR expty .
+If so, the result is the integer zero.
+The
+.B CONVERT_CAREFULLY
+macro similarly checks at compile-time that
+.I x
+has type
+.IR expty ,
+and if so, the result is
+.I x
+converted to type
+.IR newty .
+.PP
+The
+.B UNCONST
+macro checks at compile-time that
+.I p
+has (or, at least, is assignment-compatible with) type
+.BI "const " type "\ *" \fR.
+If so, it returns
+.I p
+converted to type
+.IB type "\ *" \fR,
+i.e., it removes any
+.B const
+qualification from the type that
+.I p
+points to.
+The
+.B UNVOLATILE
+macro is similar, except that it removes any
+.B volatile
+qualification;
+and the
+.B UNQUALIFY
+macro
+removes any
+.B const
+.I or
+.B volatile
+qualification.
+.PP
+The
.B COMMA
macro expands to a comma
.BR ` , ',