Hi Ian,

On 2026-02-19T10:30:09+0000, Ian Collier via Mutt-dev wrote:
> On Thu, Feb 19, 2026 at 01:46:34AM +0100, Alejandro Colomar via Mutt-dev 
> wrote:
> > On 2026-02-18T23:42:28+0000, Ian Collier via Mutt-dev wrote:
> > > I do not understand why strchrnul and strcmp are even being invoked here.
> 
> > Because they are necessary.  (Well, strcmp(3) is not, as you could do
> > manual byte operations, but it's simple, more readable, and optimized
> > out.)  strchrnul(3) is necessary.
> 
> >     strchr(s, '\0') != NULL
> 
> > would evaluate to true, which is a misbehavior: it would treat '\0' as
> > white space, while it is not. 
> 
> The nul character is a bit of an edge case when considering strxxx functions,
> of course.  But that's easily fixed:
> 
>  c && strchr(s, c) != NULL
> 
> No doubt you'll now be telling me that you don't want to evaluate c twice
> in the context of a macro.  Well then, use an inline function. :-)

An inline function with that would be an alternative.  A macro is more
compact, though, and can be implemented as a one-liner.  When
implementing several of these, it can help readability of the entire set
of APIs if they fit in a compact space and they are very similar:

        // isascii_c - is [:ascii:] C-locale
        #define isascii_c(c)   (!!strchr(CTYPE_ASCII_C, c))
        #define iscntrl_c(c)   (!!strchr(CTYPE_CNTRL_C, c))
        #define islower_c(c)   (!streq(strchrnul(CTYPE_LOWER_C, c), ""))
        #define isupper_c(c)   (!streq(strchrnul(CTYPE_UPPER_C, c), ""))
        #define isdigit_c(c)   (!streq(strchrnul(CTYPE_DIGIT_C, c), ""))
        #define ispunct_c(c)   (!streq(strchrnul(CTYPE_PUNCT_C, c), ""))
        #define isspace_c(c)   (!streq(strchrnul(CTYPE_SPACE_C, c), ""))
        #define isalpha_c(c)   (!streq(strchrnul(CTYPE_ALPHA_C, c), ""))
        #define isalnum_c(c)   (!streq(strchrnul(CTYPE_ALNUM_C, c), ""))
        #define isgraph_c(c)   (!streq(strchrnul(CTYPE_GRAPH_C, c), ""))
        #define isprint_c(c)   (!streq(strchrnul(CTYPE_PRINT_C, c), ""))
        #define isxdigit_c(c)  (!streq(strchrnul(CTYPE_XDIGIT_C, c), ""))

Here's a comparison of the assembly they produce:

        alx@devuan:~/tmp$ diff -u isspace?.c
        --- isspace1.c  2026-02-19 12:43:01.016632233 +0100
        +++ isspace2.c  2026-02-19 12:39:40.987744755 +0100
        @@ -1,8 +1,7 @@
         #include <string.h>
         #define CTYPE_SPACE_C   " \t\n\v\f\r"
        -#define streq(a,b)  (strcmp(a,b) == 0)
         bool
         isspace_c(int c)
         {
        -       return !streq(strchrnul(CTYPE_SPACE_C, c), "");
        +       return c && strchr(CTYPE_SPACE_C, c) != NULL;
         }
        alx@devuan:~/tmp$ gcc -S -O2 isspace?.c
        alx@devuan:~/tmp$ diff -u isspace?.s
        --- isspace1.s  2026-02-19 12:44:24.264776257 +0100
        +++ isspace2.s  2026-02-19 12:44:24.276776354 +0100
        @@ -1,4 +1,4 @@
        -       .file   "isspace1.c"
        +       .file   "isspace2.c"
                .text
                .section        .rodata.str1.1,"aMS",@progbits,1
         .LC0:
        @@ -10,16 +10,23 @@
         isspace_c:
         .LFB0:
                .cfi_startproc
        +       testl   %edi, %edi
        +       je      .L5
                subq    $8, %rsp
                .cfi_def_cfa_offset 16
                movl    %edi, %esi
                leaq    .LC0(%rip), %rdi
        -       call    strchrnul@PLT
        -       cmpb    $0, (%rax)
        +       call    strchr@PLT
        +       testq   %rax, %rax
                setne   %al
                addq    $8, %rsp
                .cfi_def_cfa_offset 8
                ret
        +       .p2align 4,,10
        +       .p2align 3
        +.L5:
        +       xorl    %eax, %eax
        +       ret
                .cfi_endproc
         .LFE0:
                .size   isspace_c, .-isspace_c

The strchrnul(3) version seems to have significantly less instructions.

And strchrnul(3) is internally simpler than strchr(3).  In musl, for
example, strchrnul(3) is used to implement strchr(3).


Have a lovely day!
Alex

-- 
<https://www.alejandro-colomar.es>

Attachment: signature.asc
Description: PGP signature

Reply via email to