1
\$\begingroup\$

My solution to string interpretation is pretty fast. However, I worry about repeated if (Len == 1). That might make the function bigger in the executable. How can I improve my function, to not be as redundant while checking if Len is equal to 1?

#include <ctype.h>
signed char BoolFromStr(const char *const StrIn, register const unsigned char Len) {
    if (!Len || Len > 5 || !StrIn) {
        return -1;
    }
    switch (tolower(*StrIn)) {
        case '0':
            if (Len == 1) {
                return 0;
            }
            break;
        case 'f':
            if (Len == 1 || (Len == 5 && !memcmp(Str+1, (const char[]){'a', 'l', 's', 'e'}, 4))) {
                return 0;
            }
            break;
        case 'n':
            if (Len == 1 || (Len == 2 && Str[1] == 'o')) {
                return 0;
            }
            break;
        case '1':
            if (Len == 1) {
                return 1;
            }
        case 'y':
            if (Len == 1 || (Len == 3 && !memcmp(Str+1, (const char[]){'e', 's'}, 2))) {
                return 1;
            }
            break;
        case 't':
            if (Len == 1 || (Len == 4 && !memcmp(Str+1, (const char[]){'r', 'u', 'e'}, 3))) {
                return 1;
            }
            break;
    }
    return -1;
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Is this for an embedded solution, or PC? \$\endgroup\$
    – Reinderien
    Commented Jul 21, 2020 at 2:00

1 Answer 1

2
\$\begingroup\$

How can I improve my function, to not be as redundant while checking if Len is equal to 1?

Make the null character part of the check. Len not needed anywhere.

// if (Len == 1 || (Len == 5 && !memcmp(Str+1, (const char[]){'a', 'l', 's', 'e'}, 4))) {

if (StrIn[1]==0 || !memcmp(Str+1, (const char[]){'a', 'l', 's', 'e', 0}, 5))) {
// or
if (StrIn[1]==0 || 
    (StrIn[1]=='a' && StrIn[2]=='l' && StrIn[3]=='s' && StrIn[4]=='e' && StrIn[5]==0)) {

Bug

BoolFromStr(const char *const StrIn, register const unsigned char Len) is a wrong when the length of the string is say 257 and called as

const char *s = "ttt....ttt"; // 257 t's
BoolFromStr(s, strlen(s)); // reports 1 even though `s` is not `"t"`.

Recommend size_t and drop the register. Do not tie the compilers hands.

BoolFromStr(const char *StrIn, size_t Len);

To reduce size and improve speed I'd consider a hashing of the first byte of StrIn

// Pseudo code

int BoolFromStr(const char *StrIn) {
  const char *tf[] = {"0", "1", "false", "true", "no", "yes", "", "" };
  unsigned hash = hashf(StrIn[0])%8;
  const char *cmps = tf[hash];
  if (StrIn[0] == cmps[0] && (StrIn[1] == 0 || (strcmp(StrIn, cmps) == 0))) {
    return hash & 1;
  }
}

See similar What's the fastest way to interpret a bool string into a number in C?.

\$\endgroup\$
2
  • \$\begingroup\$ 'const char *s = "ttt....ttt"; // 257 t's BoolFromStr(s, strlen(s)); // reports 1 even though s is not "t".' The issue with that is because in my program it won't be used on strings longer than like five letters \$\endgroup\$
    – user227432
    Commented Aug 11, 2020 at 18:08
  • \$\begingroup\$ @user227432 If "it won't be used on strings longer than like five letters" is true then Len > 5 test not needed either for this program. Yet the point of good coding includes re-use and avoiding writing code with too narrow an application. Keep in mind, tests like Len > 5 are useful to detect the unexpected as does avoiding type narrowing. Your call. \$\endgroup\$
    – chux
    Commented Aug 11, 2020 at 18:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.