The problem is with the sign-extension and is easy to fix.
- Consider the char value -10.
- This is "11110110" in two's-complement binary.
- Now we implicitly convert this to a signed int by passing it to isprint().
- The value is sign-extended and we now have "11111111 11111111 11111111 11110110" in binary.
- The implementation casts this value to an unsigned int for comparison purposes.
- We now have the decimal value 4294967286. Obviously, this will cause problems if we try to compare it against a 256 or 64KB lookup table.
This is demonstrated with this very simple program.
Code:
#include <stdio.h>
void demo(int c)
{
printf("int_value: %d\n", c);
printf("uint_value: %u\n", c);
}
int main(void)
{
char c = -10;
demo(c);
demo((unsigned char) c);
getchar();
return 0;
}
The solution is to avoid the sign-extension by passing the value as an unsigned char.
Code:
isprint((unsigned char) 'ö')
However, it still doesn't return true. This is because the ctype functions use the "C" locale by default. In this locale, only the base characters are supported. We can use the setlocale function or we can use Windows functions which provide much more reliable international character support.
Code:
#include <stdio.h>
#include <ctype.h>
#include <windows.h>
#include <locale.h>
int win_isprint(UCHAR c)
{
WORD char_type;
if (GetStringTypeA(LOCALE_USER_DEFAULT, CT_CTYPE1, (LPCSTR) &c, 1, &char_type))
return !(char_type & C1_CNTRL);
else
return 0;
}
int main(void)
{
char c = -10;
setlocale( LC_ALL, ".ACP" ); /* Uses the windows specified code page. */
printf("CLib: %d\n", isprint((unsigned char) '\b'));
printf("CLib: %d\n", isprint((unsigned char) 'a'));
printf("CLib: %d\n", isprint((unsigned char) 'ö'));
printf("Win: %d\n", win_isprint('ö'));
printf("Win: %d\n", win_isprint('\b'));
getchar();
return 0;
}
Results:
Code:
CLib: 0
CLib: 258
CLib: 258
Win: 1
Win: 0