isalpha(<mychar>) == true evaluates to false?
Asked Answered
P

4

5

string temp is equal to "ZERO:\t.WORD\t1" from my debugger. (the first line of my file)

string temp = RemoveWhiteSpace(data);
int i = 0;
if ( temp.length() > 0 && isalpha(temp[0]) )
    cout << "without true worked" << endl;
if ( temp.length() > 0 && isalpha(temp[0]) == true )
    cout << "with true worked" << endl;

This is my code to check if first character of temp is a a-z,A-Z. The first if statement will evaluate to true and the 2nd to false. WHY?!?!?! I have tried this even without the "temp.length() > 0 &&" and it still evaluates false. It just hates the "== true". The only thing I can think of is that isalpha() returns != 0 and true == 1. Then, you could get isalpha() == 2 != 1. But, I have no idea if C++ is that ... weird.

BTW, I dont need to know that the "== true" is logically pointless. I know.

output was

without true worked

Compiled with CodeBlock using GNU GCC on Ubuntu 9.10 (if this matters any)

Puddle answered 25/3, 2010 at 21:43 Comment(5)
Have you tried cout << isalpha(temp[0]) << endl; ?Rooke
"I have no idea if C++ is that ... weird". Consulting a reference manual would give you an idea. cplusplus.com says, "A value different from zero (i.e., true) if indeed c is an alphabetic letter". Which is why you shouldn't use cplusplus.com: true in C++ doesn't mean the same thing as "true" in the description in the C standard that they copied from. opengroup.org says, "The isalpha() function shall return non-zero if c is an alphabetic character", which is rather better.Splice
Also, beware confusion between this isalpha function from <cctype> or <ctype.h>, and the function template std::isalpha in <locale>. The latter returns bool, so if you were calling that then your code would work.Splice
Oh, and another thing, isalpha(temp[0]) is wrong. You should write isalpha((unsigned char)(temp[0])), or a static_cast if you insist. For reasons unclear to me, isalpha takes an int parameter which must be non-negative (or EOF), whereas char might be a signed type on your compiler (I believe it is if you're on Ubuntu on x86). Doesn't make a whole lot of sense, but there you go. I guess it was considered easier for callers to cast when reading from a string, than to check for EOF when reading from a stream.Splice
Other questions that addressed this from a style standpoint: #1535897 and #356717 My take is that comparing against true/false is bad style because it can lead to pitfalls like what you've run into.Anything
E
9

The is* functions are only guaranteed to return a non-zero value if true, NOT necessarily a 1. A typical implementation is table based, with one entry in the table for each character value, and a set of bits defining which bit means what. The is* function will just AND the right bitmask with the table value, and return that, which will only be the value 1 for whichever type happens to have been given bit position 0.

E.g.:

#define __digit 1
#define __lower 2
#define __upper 4
extern int __type_table[];

int isdigit(int c) { 
    return __type_table[c+1] & __digit;
}

int isalpha(int c) { 
    return __type_table[c+1] & (__lower | __upper);
}

int islower(int c) { 
    return __type_table[c+1] & __lower;
}

int isupper(int c) { 
    return __type_table[c+1] & __upper;
}

Where __type_table is defined as something like int __type_table[UINT_MAX+1]; and would be initialized so (for example) __type_table['0'+1] == __digit and __type_table['A'+1] == __upper.

In case you care, the '+1' part is to leave a spot at the beginning of the table for EOF (which is typically defined as -1).

Endosperm answered 25/3, 2010 at 21:48 Comment(5)
@Buttink:now that you mention it, that does seem odd... :-)Endosperm
@Buttink: liking C# is what got you into this mess - if it wasn't for C# you'd be happy just to use an integer in a conditional, which works, instead of comparing it to a single "truth" value, which doesn't because the C functions weren't designed for you to do that. It's fine to prefer C#, but it's not fine to pretend you're writing C# when you're really writing C++ ;-)Splice
@steve No instead a bunch of lazy f**ks decided to make a logically bool function return an int. This wouldnt even happen if C didnt allow a bool to be implicitly converted to int. In assembler, you at least assume there is no type. C is a high level lanuages.Puddle
@Buttink:C didn't have a Boolean type when these were invented either. The design wasn't about laziness either, but about efficiency. Keep in mind that C was originally intended to take the place of hand-written assembly language, and they were serious about making it as close to the same efficiency as possible. Converting every non-zero value to a 1 didn't fit with that at all. The preface to The C Programming Language (1st Edition) specifically states that "C is not a very high level language..."Endosperm
Not all that bad though. It's only required to care about ranges 0 .. UCHAR_MAX or EOF :)Reservoir
D
2

isalpha doesn't return true, it returns non-zero. This is quite common for API designed for C.

Note that in the expression isalpha(ch) == true, the subexpression true is promoted to type int with value 1.

Dortheydorthy answered 25/3, 2010 at 21:47 Comment(0)
E
0

Well, the documentation suggests that it returns either zero or non-zero, not necessarily just false or true. So you'd better check (isalpha(temp[0]) != 0).

Etty answered 25/3, 2010 at 21:48 Comment(2)
@mmyers: Or isalpha(temp[0])!Holcman
@UncleBens: Hush, you'll kill my air of superiority.Rooke
D
0

Do not isalpha(ch) == true, but !!isalpha(ch) == true

Doubtless answered 25/3, 2010 at 21:56 Comment(3)
If you're going to compare a Boolean value to true (thus producing another Boolean value) are you sure that once is enough? Maybe it should really be (!!isalpha(ch)==true)==true, or perhaps even (((((!!isalpha(ch)==true)==true)==true)==true)==true? Hey look, I've invented Lisp! :-)Endosperm
Any expression with double ! signs needs to die. It's not ideomatic, it's ugly, and it's almost certainly not what you wanted to do anyway. -1.Aga
@Jerry: I think the true connoisseur of boolean expressions starts with (!!isalpha(ch)==(!!true==!!true)), and takes it from there as the mood strikes.Splice

© 2022 - 2024 — McMap. All rights reserved.