
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).