Message ID | CAD22NBkDvgVjq2D8B4pKJQzwtp5f+1WV1nv6WyG_zajkwP7-cQ@mail.gmail.com |
---|---|
State | New |
Headers |
Return-Path: <newlib-bounces~patchwork=sourceware.org@sourceware.org> X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 873E33858D28 for <patchwork@sourceware.org>; Thu, 7 Nov 2024 16:54:15 +0000 (GMT) X-Original-To: newlib@sourceware.org Delivered-To: newlib@sourceware.org Received: from mail-qt1-x835.google.com (mail-qt1-x835.google.com [IPv6:2607:f8b0:4864:20::835]) by sourceware.org (Postfix) with ESMTPS id 37D193858D28 for <newlib@sourceware.org>; Thu, 7 Nov 2024 16:53:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 37D193858D28 Authentication-Results: sourceware.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=google.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 37D193858D28 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::835 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1730998430; cv=none; b=UOKCkREtsD+UOi7W7gjED1N9MdYMnPoR1nBpNWEqu8/i+SG6fiDH5U5m8yz+YMI21YVW+hAtz3J/3zTr6/SK4ECVhUqfzqrZ/2aJGfu6DWf3CtVmUtlZmGRhA0dMyx2lOrcWX6sVdF6dBWPw7n2YNx1tvYxcP6T/n8MNRczJD/M= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1730998430; c=relaxed/simple; bh=j2eniI0QydRs889kE2+lCIUgyqjHhwmFqG1Y+cfro0s=; h=DKIM-Signature:MIME-Version:From:Date:Message-ID:Subject:To; b=lfNg2wXRDbiYnh2Vtz96em6ayjMAcN0n9/4VZFi2dHJ5+YL0QeDaeSXo3IpWhSpQwaM0bj8miS0JbTSE46NP2n/ELZWdDmlV8ESMGztiWQqNOMjVE8+EcoLCaFpZY+7SJLe2OFw/C2+51OgxUYG9BTgtUdc5jhIq5+z138OiNvk= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-qt1-x835.google.com with SMTP id d75a77b69052e-460a8d1a9b7so261111cf.1 for <newlib@sourceware.org>; Thu, 07 Nov 2024 08:53:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1730998426; x=1731603226; darn=sourceware.org; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=bwhetHKSQA09EYyA9P2+QKxndelrzj4KoatA4QLrYrU=; b=AzudzeIItHBbNjU5j7PUqKSSehXIaMn7LDZHeFta1AsjK4XS2zZJiVwpPVa46YwhPA 8B6vm4Wan+7uI5BEOSAQM3YNqkbLD9fznSA1gNZtwy+HXv2fAubhLgaRCxVa/lf8c7HR etRlv7ahjXRoqW/vA283OqJzhLuHTYBAVi6Gc0gtA0V8RRXDSBdG3VTzzKSJI7Z7tvrj dFpgJg6XBd6jkAzm8H6RUy8jPK/xm+KtFiFBFU7vkLa16raLBYrDd35v2HzkwaTy9rBF g6gAcXV28y1oFtLQSJokst+XYWzx/bKbVtzlazDdfyvUT74RcZPXQ30GXvs799ex5V7E WhMQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730998426; x=1731603226; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=bwhetHKSQA09EYyA9P2+QKxndelrzj4KoatA4QLrYrU=; b=vhqGeCarp8kwjfP+FriKJwFdiKB7ULcvRoCs4xxa2mIv2Oo7a8IbXAA7LD8N4StgMK Twxi+d6BtzRo6DZlHntQ467ggV/oDR2k2FJkWZlIyURYfFf5KHt4IQ8+ZAdSm5nVVqaA VJ28yyIm4xby4QLz1VOumgiCH+2ixir811oF1H/qb+wrS+yZ7VU9T/F3MPathf6Kbt8E /UBB6EZAnuGhtXn1LYB9nz/hdudYn3Jb1n2O3rFNdU4q6qpcfDok0z25KD6ahPx80sbZ WlbHkyTabxBxhWDojpPWF/4gZiDL/EcaferpwnRU7xAcJx5ZeXAEl1ksIgxoQeDp7vNl ofbw== X-Gm-Message-State: AOJu0YypOFlfS+b54TGxq75CJCYecHw1wtYzclGC50DNkZUnVycGcTdk Ph1zV5LP+xmCoam6SHiG7olGY4OXBN9mHHXw0aKAT2Cpfaruvy41iy+V3cNiQmLX6NZFeY9xr0C zFwON82KgmUfFyPYqDY99k4YKt1Ax5e+xL8trkceterz0zMT9hjxvOn0= X-Gm-Gg: ASbGnctLpw/QTOIaKcKRy3dkpLLQOcPyK5MVfhGDXsD0Gy9hNm4h/MDzp8q5a8PCRz/ Wz0hcuUQACvIMX3ayr2GicKk1+2vOIBCNCD0sWTjNLaEPv/0Az1GjXaCUm+lDlg== X-Google-Smtp-Source: AGHT+IE1d2fSkk0YYMIuA8KLDHfgtt/vcLyEzKl/JdInnUMXWFbxQxr0yVAp7akrSTUN/+oFfMYpVI0QMn87lwmNj0I= X-Received: by 2002:ac8:7f82:0:b0:461:32e9:c5ee with SMTP id d75a77b69052e-462fa47a8d6mr5005801cf.0.1730998426085; Thu, 07 Nov 2024 08:53:46 -0800 (PST) MIME-Version: 1.0 From: Jeremy Bettis <jbettis@google.com> Date: Thu, 7 Nov 2024 09:53:32 -0700 Message-ID: <CAD22NBkDvgVjq2D8B4pKJQzwtp5f+1WV1nv6WyG_zajkwP7-cQ@mail.gmail.com> Subject: [PATCH] Add cast to unsigned char to strverscmp To: newlib@sourceware.org Content-Type: multipart/signed; protocol="application/pkcs7-signature"; micalg=sha-256; boundary="000000000000520f510626557a67" X-Spam-Status: No, score=-26.8 required=5.0 tests=BAYES_00, DKIMWL_WL_MED, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, ENV_AND_HDR_SPF_MATCH, GIT_PATCH_0, HTML_MESSAGE, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, USER_IN_DEF_DKIM_WL, USER_IN_DEF_SPF_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: newlib@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Newlib mailing list <newlib.sourceware.org> List-Unsubscribe: <https://sourceware.org/mailman/options/newlib>, <mailto:newlib-request@sourceware.org?subject=unsubscribe> List-Archive: <https://sourceware.org/pipermail/newlib/> List-Post: <mailto:newlib@sourceware.org> List-Help: <mailto:newlib-request@sourceware.org?subject=help> List-Subscribe: <https://sourceware.org/mailman/listinfo/newlib>, <mailto:newlib-request@sourceware.org?subject=subscribe> Errors-To: newlib-bounces~patchwork=sourceware.org@sourceware.org |
Series |
Add cast to unsigned char to strverscmp
|
|
Commit Message
Jeremy Bettis
Nov. 7, 2024, 4:53 p.m. UTC
GCC 14.2 with -Werror=sign-compare fails on this code.
Signed-off-by: Jeremy Bettis <jbettis@google.com>
---
newlib/libc/string/strverscmp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Comments
On 2024-11-07 09:53, Jeremy Bettis wrote: > GCC 14.2 with -Werror=sign-compare fails on this code. > > Signed-off-by: Jeremy Bettis <jbettis@google.com <mailto:jbettis@google.com>> > --- > newlib/libc/string/strverscmp.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/newlib/libc/string/strverscmp.c b/newlib/libc/string/strverscmp.c > index 55966335f..e86718faa 100644 > --- a/newlib/libc/string/strverscmp.c > +++ b/newlib/libc/string/strverscmp.c > @@ -76,7 +76,7 @@ int strverscmp(const char *l0, const char *r0) > else if (c!='0') z=0; > } > > - if (l[dp]<'1' + 9U && r[dp]<'1' + 9U) { I'd call that a false positive? > + if ((unsigned char)(l[dp]-'1')<9U && (unsigned char)(r[dp]-'1')<9U) { What happens when chars are '\0' or '\x80'? > /* If we're looking at non-degenerate digit sequences starting > * with nonzero digits, longest digit string is greater. */ > for (j=i; isdigit(l[j]); j++)
On Thu, Nov 7, 2024 at 1:06 PM <brian.inglis@systematicsw.ab.ca> wrote: > On 2024-11-07 09:53, Jeremy Bettis wrote: > > GCC 14.2 with -Werror=sign-compare fails on this code. > > > > Signed-off-by: Jeremy Bettis <jbettis@google.com <mailto: > jbettis@google.com>> > > --- > > newlib/libc/string/strverscmp.c | 2 +- > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > diff --git a/newlib/libc/string/strverscmp.c > b/newlib/libc/string/strverscmp.c > > index 55966335f..e86718faa 100644 > > --- a/newlib/libc/string/strverscmp.c > > +++ b/newlib/libc/string/strverscmp.c > > @@ -76,7 +76,7 @@ int strverscmp(const char *l0, const char *r0) > > else if (c!='0') z=0; > > } > > > > - if (l[dp]<'1' + 9U && r[dp]<'1' + 9U) { > > I'd call that a false positive? > Is this a side-effect of the signedness of char being unspecified and varying by architecture? I'd lean to trying to taking the U off the 9. > > + if ((unsigned char)(l[dp]-'1')<9U && (unsigned char)(r[dp]-'1')<9U) { > > What happens when chars are '\0' or '\x80'? > > > /* If we're looking at non-degenerate digit sequences starting > > * with nonzero digits, longest digit string is greater. */ > > for (j=i; isdigit(l[j]); j++) > --joel > > -- > Take care. Thanks, Brian Inglis Calgary, Alberta, Canada > > La perfection est atteinte Perfection is achieved > non pas lorsqu'il n'y a plus rien à ajouter not when there is no more to > add > mais lorsqu'il n'y a plus rien à retirer but when there is no more to > cut > -- Antoine de Saint-Exupéry >
On Nov 7 13:58, Joel Sherrill wrote: > On Thu, Nov 7, 2024 at 1:06 PM <brian.inglis@systematicsw.ab.ca> wrote: > > > On 2024-11-07 09:53, Jeremy Bettis wrote: > > > GCC 14.2 with -Werror=sign-compare fails on this code. > > > > > > Signed-off-by: Jeremy Bettis <jbettis@google.com <mailto: > > jbettis@google.com>> > > > --- > > > newlib/libc/string/strverscmp.c | 2 +- > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > > > diff --git a/newlib/libc/string/strverscmp.c > > b/newlib/libc/string/strverscmp.c > > > index 55966335f..e86718faa 100644 > > > --- a/newlib/libc/string/strverscmp.c > > > +++ b/newlib/libc/string/strverscmp.c > > > @@ -76,7 +76,7 @@ int strverscmp(const char *l0, const char *r0) > > > else if (c!='0') z=0; > > > } > > > > > > - if (l[dp]<'1' + 9U && r[dp]<'1' + 9U) { I'm puzzled. This doesn't look like newlib code. Newlib's code looks like this: if (l[dp]-'1'<9U && r[dp]-'1'<9U) { See https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libc/string/strverscmp.c;hb=HEAD#l79 Given that l and r are unsigned char anyway, the entire expression is unsigned, so there shouldn't be a sign-compare error in newlib's version. Corinna
On Fri, Nov 8 2024 at 11:28:31 AM +0000, Steven J Abner <pheonix.sja@att.net> wrote: > On Fri, Nov 8 2024 at 10:49:31 AM +0000, Corinna Vinschen > <vinschen@redhat.com> wrote: >> l[dp]-'1' > > I'm not an expert on gcc, but most of the time this trips me up, gcc > math. Gcc might be converting to int32_t to do sub/add of variables. > Steve >
Corinna Vinschen wrote: > On Nov 7 13:58, Joel Sherrill wrote: >> On Thu, Nov 7, 2024 at 1:06 PM <brian.inglis@systematicsw.ab.ca> wrote: >> >>> On 2024-11-07 09:53, Jeremy Bettis wrote: >>>> GCC 14.2 with -Werror=sign-compare fails on this code. >>>> >>>> Signed-off-by: Jeremy Bettis <jbettis@google.com <mailto: >>> jbettis@google.com>> >>>> --- >>>> newlib/libc/string/strverscmp.c | 2 +- >>>> 1 file changed, 1 insertion(+), 1 deletion(-) >>>> >>>> diff --git a/newlib/libc/string/strverscmp.c >>> b/newlib/libc/string/strverscmp.c >>>> index 55966335f..e86718faa 100644 >>>> --- a/newlib/libc/string/strverscmp.c >>>> +++ b/newlib/libc/string/strverscmp.c >>>> @@ -76,7 +76,7 @@ int strverscmp(const char *l0, const char *r0) >>>> else if (c!='0') z=0; >>>> } >>>> >>>> - if (l[dp]<'1' + 9U && r[dp]<'1' + 9U) { > I'm puzzled. This doesn't look like newlib code. Newlib's code looks > like this: > > if (l[dp]-'1'<9U && r[dp]-'1'<9U) { > > See https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libc/string/strverscmp.c;hb=HEAD#l79 > > Given that l and r are unsigned char anyway, the entire expression > is unsigned, so there shouldn't be a sign-compare error in newlib's > version. > It's actually signed, IIRC due to changing 'unsigned preserving' (K&R C) to 'value preserving' (C89) implicit conversions. "Proof" using C++17 compile time checks: $ cat uchar2int.cc #include <cstddef> #include <type_traits> const unsigned char *l; std::size_t dp; static_assert(std::is_same_v<decltype(l[dp]), const unsigned char &>); static_assert(std::is_same_v<decltype(l[dp]-'1'), int>); static_assert(std::is_same_v<decltype(l[dp]-0x31U), unsigned int>); $ g++ -S -Wall -W uchar2int.cc [no failed assert]
On Nov 8 12:41, Christian Franke wrote: > Corinna Vinschen wrote: > > On Nov 7 13:58, Joel Sherrill wrote: > > > On Thu, Nov 7, 2024 at 1:06 PM <brian.inglis@systematicsw.ab.ca> wrote: > > > > > > > On 2024-11-07 09:53, Jeremy Bettis wrote: > > > > > GCC 14.2 with -Werror=sign-compare fails on this code. > > > > > > > > > > Signed-off-by: Jeremy Bettis <jbettis@google.com <mailto: > > > > jbettis@google.com>> > > > > > --- > > > > > newlib/libc/string/strverscmp.c | 2 +- > > > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > > > > > > > diff --git a/newlib/libc/string/strverscmp.c > > > > b/newlib/libc/string/strverscmp.c > > > > > index 55966335f..e86718faa 100644 > > > > > --- a/newlib/libc/string/strverscmp.c > > > > > +++ b/newlib/libc/string/strverscmp.c > > > > > @@ -76,7 +76,7 @@ int strverscmp(const char *l0, const char *r0) > > > > > else if (c!='0') z=0; > > > > > } > > > > > > > > > > - if (l[dp]<'1' + 9U && r[dp]<'1' + 9U) { > > I'm puzzled. This doesn't look like newlib code. Newlib's code looks > > like this: > > > > if (l[dp]-'1'<9U && r[dp]-'1'<9U) { > > > > See https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libc/string/strverscmp.c;hb=HEAD#l79 > > > > Given that l and r are unsigned char anyway, the entire expression > > is unsigned, so there shouldn't be a sign-compare error in newlib's > > version. > > > > It's actually signed, IIRC due to changing 'unsigned preserving' (K&R C) to > 'value preserving' (C89) implicit conversions. > > "Proof" using C++17 compile time checks: > > $ cat uchar2int.cc > #include <cstddef> > #include <type_traits> > > const unsigned char *l; > std::size_t dp; > > static_assert(std::is_same_v<decltype(l[dp]), const unsigned char &>); > static_assert(std::is_same_v<decltype(l[dp]-'1'), int>); > static_assert(std::is_same_v<decltype(l[dp]-0x31U), unsigned int>); > > $ g++ -S -Wall -W uchar2int.cc > [no failed assert] Drat. Looks like I'm still living in K&R country... Corinna
On Nov 8 15:37, Corinna Vinschen wrote: > On Nov 8 12:41, Christian Franke wrote: > > Corinna Vinschen wrote: > > > On Nov 7 13:58, Joel Sherrill wrote: > > > > On Thu, Nov 7, 2024 at 1:06 PM <brian.inglis@systematicsw.ab.ca> wrote: > > > > > > > > > On 2024-11-07 09:53, Jeremy Bettis wrote: > > > > > > GCC 14.2 with -Werror=sign-compare fails on this code. > > > > > > > > > > > > Signed-off-by: Jeremy Bettis <jbettis@google.com <mailto: > > > > > jbettis@google.com>> > > > > > > --- > > > > > > newlib/libc/string/strverscmp.c | 2 +- > > > > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > > > > > > > > > diff --git a/newlib/libc/string/strverscmp.c > > > > > b/newlib/libc/string/strverscmp.c > > > > > > index 55966335f..e86718faa 100644 > > > > > > --- a/newlib/libc/string/strverscmp.c > > > > > > +++ b/newlib/libc/string/strverscmp.c > > > > > > @@ -76,7 +76,7 @@ int strverscmp(const char *l0, const char *r0) > > > > > > else if (c!='0') z=0; > > > > > > } > > > > > > > > > > > > - if (l[dp]<'1' + 9U && r[dp]<'1' + 9U) { > > > I'm puzzled. This doesn't look like newlib code. Newlib's code looks > > > like this: > > > > > > if (l[dp]-'1'<9U && r[dp]-'1'<9U) { > > > > > > See https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libc/string/strverscmp.c;hb=HEAD#l79 > > > > > > Given that l and r are unsigned char anyway, the entire expression > > > is unsigned, so there shouldn't be a sign-compare error in newlib's > > > version. > > > > > > > It's actually signed, IIRC due to changing 'unsigned preserving' (K&R C) to > > 'value preserving' (C89) implicit conversions. > > > > "Proof" using C++17 compile time checks: > > > > $ cat uchar2int.cc > > #include <cstddef> > > #include <type_traits> > > > > const unsigned char *l; > > std::size_t dp; > > > > static_assert(std::is_same_v<decltype(l[dp]), const unsigned char &>); > > static_assert(std::is_same_v<decltype(l[dp]-'1'), int>); > > static_assert(std::is_same_v<decltype(l[dp]-0x31U), unsigned int>); > > > > $ g++ -S -Wall -W uchar2int.cc > > [no failed assert] > > Drat. Looks like I'm still living in K&R country... So then, what about if (l[dp]-U'1'<9U && r[dp]-U'1'<9U) { At least static_assert(std::is_same_v<decltype(l[dp]-U'1'), unsigned int>); is happy. Corinna
Am 08.11.2024 um 12:41 schrieb Christian Franke: > Corinna Vinschen wrote: >> On Nov 7 13:58, Joel Sherrill wrote: >> Given that l and r are unsigned char anyway, the entire expression >> is unsigned, so there shouldn't be a sign-compare error in newlib's >> version. > It's actually signed, IIRC due to changing 'unsigned preserving' (K&R C) > to 'value preserving' (C89) implicit conversions. The reason it's signed is because '1' is a signed integer, so this expression has a type train of: ((unsigned char) - (signed int)) < (unsigned int) The left hand side of the < operator is signed int on all but the very weirdest architectures (think sizeof(int) == 1), as unsigned char undergoes integer promotion to signed int on those. As to using U'1' to work around this quirk: that's a C11-ism. YMMV.
Corinna Vinschen wrote: > On Nov 8 15:37, Corinna Vinschen wrote: >> On Nov 8 12:41, Christian Franke wrote: >>> Corinna Vinschen wrote: >>>> On Nov 7 13:58, Joel Sherrill wrote: >>>>> On Thu, Nov 7, 2024 at 1:06 PM <brian.inglis@systematicsw.ab.ca> wrote: >>>>> >>>>>> On 2024-11-07 09:53, Jeremy Bettis wrote: >>>>>>> GCC 14.2 with -Werror=sign-compare fails on this code. >>>>>>> >>>>>>> Signed-off-by: Jeremy Bettis <jbettis@google.com <mailto: >>>>>> jbettis@google.com>> >>>>>>> --- >>>>>>> newlib/libc/string/strverscmp.c | 2 +- >>>>>>> 1 file changed, 1 insertion(+), 1 deletion(-) >>>>>>> >>>>>>> diff --git a/newlib/libc/string/strverscmp.c >>>>>> b/newlib/libc/string/strverscmp.c >>>>>>> index 55966335f..e86718faa 100644 >>>>>>> --- a/newlib/libc/string/strverscmp.c >>>>>>> +++ b/newlib/libc/string/strverscmp.c >>>>>>> @@ -76,7 +76,7 @@ int strverscmp(const char *l0, const char *r0) >>>>>>> else if (c!='0') z=0; >>>>>>> } >>>>>>> >>>>>>> - if (l[dp]<'1' + 9U && r[dp]<'1' + 9U) { >>>> I'm puzzled. This doesn't look like newlib code. Newlib's code looks >>>> like this: >>>> >>>> if (l[dp]-'1'<9U && r[dp]-'1'<9U) { >>>> >>>> See https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=newlib/libc/string/strverscmp.c;hb=HEAD#l79 >>>> >>>> Given that l and r are unsigned char anyway, the entire expression >>>> is unsigned, so there shouldn't be a sign-compare error in newlib's >>>> version. >>>> >>> It's actually signed, IIRC due to changing 'unsigned preserving' (K&R C) to >>> 'value preserving' (C89) implicit conversions. >>> >>> "Proof" using C++17 compile time checks: >>> >>> $ cat uchar2int.cc >>> #include <cstddef> >>> #include <type_traits> >>> >>> const unsigned char *l; >>> std::size_t dp; >>> >>> static_assert(std::is_same_v<decltype(l[dp]), const unsigned char &>); >>> static_assert(std::is_same_v<decltype(l[dp]-'1'), int>); >>> static_assert(std::is_same_v<decltype(l[dp]-0x31U), unsigned int>); >>> >>> $ g++ -S -Wall -W uchar2int.cc >>> [no failed assert] >> Drat. Looks like I'm still living in K&R country... > So then, what about > > if (l[dp]-U'1'<9U && r[dp]-U'1'<9U) { > > At least > > static_assert(std::is_same_v<decltype(l[dp]-U'1'), unsigned int>); > > is happy. > In practice, this should work for all existing use cases of newlib. In theory, it is not generally portable: U'1' has type char32_t (C11) which is unsigned. If the very rare ILP64 data model would be used, this would be promoted to 64-bit signed int. This variant does not depend on signedness or integer overflow: if ('1' <= l[dp] && l[dp] <= '9' && '1' <= r[dp] && r[dp] <= '9') {
Hans-Bernhard Bröker wrote: > Am 08.11.2024 um 12:41 schrieb Christian Franke: >> Corinna Vinschen wrote: >>> On Nov 7 13:58, Joel Sherrill wrote: > >>> Given that l and r are unsigned char anyway, the entire expression >>> is unsigned, so there shouldn't be a sign-compare error in newlib's >>> version. > >> It's actually signed, IIRC due to changing 'unsigned preserving' (K&R >> C) to 'value preserving' (C89) implicit conversions. > > The reason it's signed is because '1' is a signed integer, so this > expression has a type train of: > > ((unsigned char) - (signed int)) < (unsigned int) The LHS of '<' is signed because both arguments are signed after implicit integer promotion: ((signed int)(unsigned char) - (signed int)) < (unsigned int) In traditional K&R C, it was unsigned: ((unsigned int)(unsigned char) - (signed int)) < (unsigned int)
Am 08.11.2024 um 18:36 schrieb Christian Franke: > This variant does not depend on signedness or integer overflow: > > if ('1' <= l[dp] && l[dp] <= '9' && '1' <= r[dp] && r[dp] <= '9') { Or one could actually use isdigit() for what it's intended to do? Yeah right, that would be just too ridiculous to even consider...
Hans-Bernhard Bröker wrote: > Am 08.11.2024 um 18:36 schrieb Christian Franke: > >> This variant does not depend on signedness or integer overflow: >> >> if ('1' <= l[dp] && l[dp] <= '9' && '1' <= r[dp] && r[dp] <= '9') { > > Or one could actually use isdigit() for what it's intended to do? Yeah > right, that would be just too ridiculous to even consider... > > No, because the '0' is intentionally excluded here. I never use isdigit() in my own code because it forbids to directly pass negative signed char values and typically results in unnecessary (locale specific) code. "Proof" for newlib: int isdigit_slow(int c) { return isdigit(c); } int isdigit_fast(int c) { return ('0' <= c && c <= '9'); } Code generated with 'gcc -O2 ...': isdigit_slow: pushq %rbx subq $32, %rsp movslq %ecx, %rbx call __locale_ctype_ptr movzbl 1(%rbx,%rax), %eax andl $4, %eax addq $32, %rsp popq %rbx ret isdigit_fast: xorl %eax, %eax subl $48, %ecx cmpl $9, %ecx setbe %al ret Speedup factor is somewhere between 5x and 10x. If compiled as C++ with 'g++ -O2 ...', identical (fast) code is generated for both functions. This is because the is*() macros in ctype.h are disabled for C++. Then GCC uses its builtin isdigit(). Not really consistent, IMO :-)
diff --git a/newlib/libc/string/strverscmp.c b/newlib/libc/string/strverscmp.c index 55966335f..e86718faa 100644 --- a/newlib/libc/string/strverscmp.c +++ b/newlib/libc/string/strverscmp.c @@ -76,7 +76,7 @@ int strverscmp(const char *l0, const char *r0) else if (c!='0') z=0; } - if (l[dp]<'1' + 9U && r[dp]<'1' + 9U) { + if ((unsigned char)(l[dp]-'1')<9U && (unsigned char)(r[dp]-'1')<9U) { /* If we're looking at non-degenerate digit sequences starting * with nonzero digits, longest digit string is greater. */ for (j=i; isdigit(l[j]); j++)