Re: [PATCH 1/2] testing/selftests: Add tests for the is_signed_type() macro
From: Rasmus Villemoes
Date: Tue Aug 30 2022 - 05:41:42 EST
On 26/08/2022 18.21, Bart Van Assche wrote:
> Although not documented, is_signed_type() must support the 'bool' and
> pointer types next to scalar and enumeration types. Add a selftest that
> verifies that this macro handles all supported types correctly.
>
> +static void is_signed_type_test(struct kunit *test)
> +{
> + KUNIT_EXPECT_EQ(test, is_signed_type(bool), false);
> + KUNIT_EXPECT_EQ(test, is_signed_type(signed char), true);
> + KUNIT_EXPECT_EQ(test, is_signed_type(unsigned char), false);
Nice. You could consider adding
#ifdef __UNSIGNED_CHAR__
KUNIT_EXPECT_EQ(test, is_signed_type(char), false);
#else
KUNIT_EXPECT_EQ(test, is_signed_type(char), true);
#endif
The kernel depends on the compiler providing __UNSIGNED_CHAR__ in two
places (one in ext4, one in printf test suite).
> + KUNIT_EXPECT_EQ(test, is_signed_type(int), true);
> + KUNIT_EXPECT_EQ(test, is_signed_type(unsigned int), false);
> + KUNIT_EXPECT_EQ(test, is_signed_type(long), true);
> + KUNIT_EXPECT_EQ(test, is_signed_type(unsigned long), false);
> + KUNIT_EXPECT_EQ(test, is_signed_type(long long), true);
> + KUNIT_EXPECT_EQ(test, is_signed_type(unsigned long long), false);
> + KUNIT_EXPECT_EQ(test, is_signed_type(enum unsigned_enum), false);
> + KUNIT_EXPECT_EQ(test, is_signed_type(enum signed_enum), true);
Yeah. But enum types are one of the weirdest aspects of C. Taking your
example and expanding with a positive value that doesn't fit an int:
#include <stdio.h>
#define is_signed_type(t) ((t)-1 < (t)1)
#define typeinfo(t) printf("%-24s signed %d, size %zu\n", #t,
is_signed_type(t), sizeof(t))
enum unsigned_enum {
constant_a = 3,
constant_d = 3000000000,
};
enum signed_enum {
constant_b = -1,
constant_c = 2,
};
int main(int argc, char *argv[])
{
enum unsigned_enum a = constant_a;
enum unsigned_enum d = constant_d;
enum signed_enum b = constant_b;
enum signed_enum c = constant_c;
typeinfo(enum unsigned_enum);
typeinfo(enum signed_enum);
typeinfo(typeof(constant_a));
typeinfo(typeof(constant_b));
typeinfo(typeof(constant_c));
typeinfo(typeof(constant_d));
typeinfo(typeof(a));
typeinfo(typeof(b));
typeinfo(typeof(c));
typeinfo(typeof(d));
return 0;
}
This gives me
enum unsigned_enum signed 0, size 4
enum signed_enum signed 1, size 4
typeof(constant_a) signed 1, size 4
typeof(constant_b) signed 1, size 4
typeof(constant_c) signed 1, size 4
typeof(constant_d) signed 0, size 4
typeof(a) signed 0, size 4
typeof(b) signed 1, size 4
typeof(c) signed 1, size 4
typeof(d) signed 0, size 4
That is, typeof(constant_a) is not the same type (different signedness)
as enum unsigned_enum! While both constant_d (due to its size) and
variables declared as 'enum unsigned_enum' do indeed have that
underlying unsigned type.
At least gcc and clang agree on this weirdness, but I haven't been able
to find a spec mandating this. Anyway, this was just an aside.
Acked-by: Rasmus Villemoes <linux@xxxxxxxxxxxxxxxxxx>