0
\$\begingroup\$

I have a function to check if a character is a delimiter and I wonder if it is consistent or can be improved:

int chDelimit(int ch)
{
    return
        (ch == '\n' || ch == '\t') ||
        (ch >= ' ' && ch <= '/') ||
        (ch >= ':' && ch <= '@') ||
        (ch >= '[' && ch <= '`') ||
        (ch >= '{' && ch <= '~') ||
        (ch == '\0');
}
\$\endgroup\$
  • 2
    \$\begingroup\$ Can you add a description of what a delimiter is in this case? What one program considers a delimiter, another might not. \$\endgroup\$ – pacmaninbw Apr 10 at 12:34
5
\$\begingroup\$

There's no particular ordering of characters' code-points in C (other than the digits 0..9). This code assumes (for example) that '[' is less than '`', but that's not the case in EBCDIC at least.

I think you might be better off creating a table of boolean values, and indexing into that with the (unsigned value of) ch, in the way that standard <ctype.h> functions are normally implemented. This will probably improve performance (one lookup, rather than up to 11 comparisons, per call).

Alternatively, and depending on what characters are considered "delimiters", you may be able to use standard library functions (e.g. isalnum()) in combination.

\$\endgroup\$
4
\$\begingroup\$
  1. Function Name It isn't clear that chDelimit() is a function that tests whether a character is a delimiter character. For functions that return boolean, it's generally accepted to call it Is<Condition>() where condition is phrased in the affirmative. For example, I'd name this function IsDelimiter() and not IsNonDelimiterCharacter()

  2. Depending on your application, it might be worthwhile to create macros for boolean values (or enums). See SO: Using Boolean Values in C

  3. If the list of delimiter characters isn't going to grow too large, create a character array, DelimiterCharacters, and have your function do a one-pass search.

\$\endgroup\$
1
\$\begingroup\$

Strictly speaking you can't assume that the various characters are in range, portably. The only characters actually guaranteed to be located in a continuous range in the symbol table are '0' to '9'. That's mostly a nitpick though, since 99.9% of all systems are ASCII or UTF.

What's more serious is that this look-up is slow. You have numerous branches which the CPU must execute. If you have to call this function repeatedly from a loop, it will be performance-heavy. Instead, you can replace all of this with a look-up table.

For boolean checks, you should be using bool.

A fixed function might look like this:

#include <stdbool.h>

bool isdelimit (char ch)
{
  ch &= 0x7F; // ensure 7 bit 

  const bool DELIMIT[128] = 
  {
    ['\n'] = true,
    ['\t'] = true,
    [' ']  = true,
    ['\0'] = true,
    // ...
  };
  return DELIMIT[ch];
}

The table DELIMIT will per default initialize all items to false save for those that you explicitly initialize. By using the character value as the search key, the algorithm turns branchless and efficient.

The above trick with using designated initializers means that you only need to type out those delimiters you are interested in, rather than typing out a big table of 127 values.

Also check out the rarely used but 100% standard C functions strpbrk and strcspn (string.h) that can be used for this very purpose too.

\$\endgroup\$
  • \$\begingroup\$ This designated initializer is a very cool idea. \$\endgroup\$ – machine_1 Apr 12 at 13:46
  • \$\begingroup\$ 99+% of systems are Extended ASCII, like UTF-8, Latin-1, ASCII+Don'tCare, and so on, at least leaving out other wider UTFs. Few are vanilla ASCII. \$\endgroup\$ – Deduplicator Apr 12 at 13:58
  • \$\begingroup\$ @Deduplicator With ASCII being a subset of them all. \$\endgroup\$ – Lundin Apr 12 at 14:02
  • \$\begingroup\$ I'd expect values outside the 0...7F range to return false, not ignore the 8th bit. Simple enough to use const bool DELIMIT256[UCHAR_MAX + 1] and static const bool DELIMIT[(unsigned char) ch]; \$\endgroup\$ – chux - Reinstate Monica Apr 12 at 22:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.