Path: csiph.com!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: size_t best practice Date: Thu, 22 Aug 2024 01:31:01 -0700 Organization: A noiseless patient Spider Lines: 60 Message-ID: <86ed6h9cxm.fsf@linuxsc.com> References: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Date: Thu, 22 Aug 2024 10:31:02 +0200 (CEST) Injection-Info: dont-email.me; posting-host="dd674af37156d5461d600da65dab9de0"; logging-data="405193"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19nAZysBMbqNsl3TGM8RtZkyOlkQ04a7B0=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:ZlkFFwE+70adyPl0TSK75CejtnE= sha1:2WtdIsYX2i5nyJyOFxjmwJpL30o= Xref: csiph.com comp.lang.c:387682 Andrey Tarasevich writes: > On 08/18/24 1:03 AM, Mark Summerfield wrote: > >> However, this means I have to be very careful never to decrement a >> size_t of value 0, since, e.g., size_t size = 0; size--; results in >> size == 18446744073709551615. > > That's a completely incorrect conclusion. There's nothing wrong > with decrementing a 0 of type `size_t`. It results in perfectly > defined behavior. It produces a `(size_t) -1` value. > > For example, iteration all the way to 0 can be idiomatically > implemented as > > for (some_unsigned_type i = size; (some_unsigned_type) i != -1; --i) > ... > > This will work, even though it will eventually decrement a zero > value. If you are sure that the type is "large" (e.g. `int` or > larger), then the cast is unnecessary > > for (some_unsigned_type i = size; i != -1; --i) > ... > > (Note, BTW, that it also works perfectly for signed index types.) > > >> So I need to guard against this. Here is an example I'm using >> (without the assert()s): >> >> void vec_insert(vec* v, size_t index, void* value) { >> if (v->_size == v->_cap) { >> vec_grow(v); >> } >> for (size_t i = v->_size - 1; i >= index; --i) { >> v->_values[i + 1] = v->_values[i]; >> if (!i) // if i == 0, --i will wrap! >> break; >> } >> v->_values[index] = value; >> v->_size++; >> } > > No, that's rather weird and unnecessarily overwrought way to guard > against this. > > We can immediately apply the pattern I demonstrated above to this > and get > > for (size_t i = v->_size - 1; i != index - 1; --i) > v->_values[i + 1] = v->_values[i]; > > Done. No need for an extra safeguard. Better (please ignore cosmetic layout differences): for( size_t i = v->_size; i > index; i-- ){ v->_values[i] = v->_values[i-1]; }