Ctype Functions: isascii() and iscntrl()


I almost believe these two functions to be useless, but they do play an important role in the ctype pantheon: isascii() determines whether an integer value is an ASCII character, and iscntrl() lets the program know further whether an integer value is also an ASCII control code. This pair adds to my continuing exploration of the ctype functions.

Here are the specific definitions:

The isascii() function returns TRUE when the value of its integer argument is in the range of zero through 127, the ASCII code values. (ASCII represents unsigned char values, but the function’s argument is an int data type.)

The iscntrl() function returns TRUE when the value of its integer argument is in the range of ASCII codes zero through 31 plus the DEL character, code 127. These are all unprintable characters, though some affect the cursor’s position.

To test these two functions, I wrote code that generates 20 random values in the range of zero through 255. For each value generated, a line is output showing its decimal and hexadecimal values, as well as its Unicode character representation. Then the code explains whether the value is ASCII, non-ASCII, or a control code. It’s assumed that all control codes are ASCII values by definition.

2026_06_13-Lesson-a.c

#include <locale.h>
#include <wchar.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>

int main()
{
    int x,r;

    /* seed the randomizer */
    srand( (unsigned)time(NULL) );

    /* set the locale for wide characters */
    setlocale(LC_ALL,"");

    /* generate and evaluate 20 random chars */
    for( x=0; x<20; x++ )
    {
        r = rand() % 0xFF;    /* char range */
        wprintf(L"%03d %02X ",r,r);
        if( isascii(r) )
        {
            if( iscntrl(r) )
            {
                /* call out DEL */
                if( r==127 )
                    wprintf(L"%lc - control code",9249);
                /* other Unicode ctrl chars */
                else
                    wprintf(L"%lc - control code",r+9216);
            }
            else
                wprintf(L"%lc - ASCII",r);
        }
        else
        {
            wprintf(L"%lc - non-ASCII",0xB7);    /* B7 = dot */
        }
        putwchar(L'\n');
    }

    return 0;
}

Testing for ASCII and control code values takes place in the for loop. An if-else decision determines whether the character is ASCII. If not (else), a dot character is output along with the text “non-ASCII.” When an ASCII character is found, the iscntrl() function checks for a control code value. If true, the control code’s Unicode character is output, otherwise the ASCII character is output.

Here is a sample run:

173 AD · - non-ASCII
054 36 6 - ASCII
038 26 & - ASCII
038 26 & - ASCII
218 DA · - non-ASCII
065 41 A - ASCII
218 DA · - non-ASCII
247 F7 · - non-ASCII
097 61 a - ASCII
160 A0 · - non-ASCII
075 4B K - ASCII
072 48 H - ASCII
012 0C ␌ - control code
122 7A z - ASCII
070 46 F - ASCII
035 23 # - ASCII
164 A4 · - non-ASCII
157 9D · - non-ASCII
002 02 ␂ - control code
110 6E n - ASCII

Emulating these functions requires a range test. For ASCII characters, the integer range is from zero through 127; for control codes the range is from zero through 31. My isascii() and iscntrl() functions use this range and return values true or false accordingly:

2026_06_13-Lesson-b.c

#include <locale.h>
#include <wchar.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>

/* is the character ASCII? */
int isascii(int c)
{
    if( c>=0 && c<=127 )
        return true;
    else
        return false;
}

/* is the character a control code? */
int iscntrl(int c)
{
    if( (c>=0 && c<=31) || c==127 )
        return true;
    else
        return false;
}

int main()
{
    int x,r;

    /* seed the randomizer */
    srand( (unsigned)time(NULL) );

    /* set the locale for wide characters */
    setlocale(LC_ALL,"");

    /* generate and evaluate 20 random chars */
    for( x=0; x<20; x++ )
    {
        r = rand() % 0xFF;    /* char range */
        wprintf(L"%03d %02X ",r,r);
        if( isascii(r) )
        {
            if( iscntrl(r) )
            {
                /* call out DEL */
                if( r==127 )
                    wprintf(L"%lc - control code",9249);
                /* other Unicode ctrl chars */
                else
                    wprintf(L"%lc - control code",r+9216);
            }
            else
                wprintf(L"%lc - ASCII",r);
        }
        else
        {
            wprintf(L"%lc - non-ASCII",0xB7);    /* B7 = dot */
        }
        putwchar(L'\n');
    }

    return 0;
}

The program’s output is the same.

These functions are necessary when processing data to look for and weed out ASCII characters as well as control codes. Even so, I don’t think I’ve ever used them. I just use the same range check as shown in my functions (above).

For next week’s Lesson, I cover the ctype function ispunct(), which is not the same is ispunked(), which isn’t a C language function at all (though it can be if you want to code it).

Leave a Reply