Messages in this thread | | | Date | Tue, 30 Aug 2022 11:41:31 +0200 | Subject | Re: [PATCH 1/2] testing/selftests: Add tests for the is_signed_type() macro | From | Rasmus Villemoes <> |
| |
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@rasmusvillemoes.dk>
| |