This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH] support: Add TEST_COMPARE macro
Florian Weimer wrote:
comparisons between actual and
expected values often have differing types. Concrete types vary between
architectures, and not just their sizes (e.g., 32-bit architectures use longs
where 64-bit architectures use int).
Yes, but I'm still not seeing the motivation for doing this via a run-time test
rather than a compile-time test. Can you show an example or two of problems that
the signedness part of this macro will fix?
Also, why can't we rely on -Wsign-compare to warn about these problems?
As for what I have in mind for a compile-time test, please see the attached
code. This also checks for floating-point types, and it avoids a false alarm in
some cases when a narrower-than-int unsigned type is promoted (that's what the
"+ (a)" and "+ (b)" are for). Finally, it suppresses -Wtype-limits since those
GCC warnings are counterproductive in this kind of code.
#pragma GCC diagnostic ignored "-Wtype-limits"
#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
#define TYPE_IS_SIGNED(t) ((t) -1 < (t) 0)
#define TYPE_FITS_IN_LONG_LONG(t) \
(sizeof (t) <= sizeof (long long) && TYPE_IS_INTEGER (t))
#define TEST_COMPARE(a, b) \
({ \
typedef __typeof__ (a) __ta; \
typedef __typeof__ (b) __tb; \
__ta __va = (a); \
__tb __vb = (b); \
\
/* Prevent accidental use with types that do not fit in long long. */ \
_Static_assert (TYPE_FITS_IN_LONG_LONG (__ta), \
"left value fits into long long"); \
_Static_assert (TYPE_FITS_IN_LONG_LONG (__tb), \
"right value fits into long long"); \
\
/* Prevent accidental use with types that might not be compared
numerically. The comparison is safe if the signedness of A and
B agree or if the unsigned value is narrower than the promoted
signed value. */ \
_Static_assert \
((TYPE_IS_SIGNED (__ta) == TYPE_IS_SIGNED (__tb) \
|| (TYPE_IS_SIGNED (__ta) && sizeof (__tb) < sizeof + (a)) \
|| (TYPE_IS_SIGNED (__tb) && sizeof (__ta) < sizeof + (b))), \
"TEST_COMPARE args might not compare numerically"); \
\
/* Report an error at run-time if A does not equal B. */ \
if (__va != __vb) \
support_test_compare_failure \
(__FILE__, __LINE__, \
#a, __va, __va < 0, \
#b, __vb, __vb < 0); \
})
void support_test_compare_failure (const char *file, int line,
const char *left_expr,
long long left_value,
_Bool left_negative,
const char *right_expr,
long long right_value,
_Bool right_negative);
int main (void)
{
TEST_COMPARE (0, 1);
TEST_COMPARE (0u, 1);
TEST_COMPARE ((unsigned short) 0, 1);
}