Re: git: c18a16ebcf5b - main - kern_proc_kqueues_out(): maxlen == -1 means there is no maxlen

From: Mark Millard <marklmi_at_yahoo.com>
Date: Tue, 25 Mar 2025 02:42:11 UTC
Olivier Certner <olce_at_freebsd.org> wrote on
Date: Mon, 24 Mar 2025 15:59:20 UTC "

> > (snip) 
> > > + if (maxlen == -1 || maxlen == 0)
> > As maxlen is of the unsigned type size_t, how can it be -1?
> > Or am I mistaken on this?
> 
> It's of course true that 'maxlen' can't be -1 mathematically as it has an unsigned type, but that's not what 'maxlen == -1' tests. In this example, 'maxlen' is an unsigned type of size at least equal to 'unsigned int', whose values cannot all be represented in a signed 'int' (well, that last part is true but not the real reason, which has to do with integer ranks). According to the standard promotion rules, and because -1 as an integer constant is interpreted as of type 'int', both arguments of '==' will be converted to 'unsigned int', and conversion of a signed type to an unsigned one is done by computing its congruence to the number of values the latter can represent (this is the mathematical description; with two-complement representation, that's basically just truncating the bits that are "too high", or sign-extending if the unsigned type destination is wider, and in this precise case, just keeping the same exact representation bits). So, basically, this test is equivalent to 'maxlen == UINT_MAX' on 32-bit machines or 'maxlen == ULONG_MAX' on 64-bit ones.
> 
> Relevant C standard passages are, in section Language > Conversions > Arithmetic operands, the "Boolean, characters, and integers", "Signed and unsigned integers" and "Usual arithmetic conversions" chapters, and, under Language > Expressions, the chapter about equality operators (in particular, the fact that it states that the usual arithmetic conversions apply), and chapter Language > Lexical elements > Constants > Integer constants.

(This does not invalidate the above material.)


Another, longer C23 notation that avoids implicit "usual
arithmetic conversions" for == (or !=) and avoids any
involvement of signed types when maxlen is unsigned:

maxlen == ~(typeof(maxlen))0u

It also has the property of the notation surviving various
type changes to maxlen that are still unsigned, without
needing editing.


These days (C23) there are parts of the language for which
implicit conversions are not involved:

QUOTE (from N3220):
The constraints for constexpr objects are intended to enforce
checks for portability at translation time.

constexpr unsigned int minusOne = -1;  // constraint violation
constexpr unsigned int uint_max = -1U; // ok
. . .
END QUOTE

Also: "An object declared with the constexpr specifier stores
the exact value of its initializer, no implicit value change
is applied."

===
Mark Millard
marklmi at yahoo.com