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)

David Stocking
  • 1,200
  • 15
  • 26
  • 1
    Have you tried `cout << isalpha(temp[0]) << endl;` ? – Michael Myers Mar 25 '10 at 21:46
  • "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. – Steve Jessop Mar 25 '10 at 22:14
  • Also, beware confusion between this isalpha function from `` or ``, and the function template `std::isalpha` in ``. The latter returns `bool`, so if you were calling that then your code would work. – Steve Jessop Mar 25 '10 at 22:19
  • 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. – Steve Jessop Mar 25 '10 at 22:33
  • Other questions that addressed this from a style standpoint: http://stackoverflow.com/questions/1535397/boolean-code-clarity-which-style-to-use/1535562#1535562 and http://stackoverflow.com/questions/356217/should-i-use-isgood-or-isgood-false/356709#356709 My take is that comparing against `true`/`false` is bad style because it can lead to pitfalls like what you've run into. – Michael Burr Mar 25 '10 at 23:15

4 Answers4

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

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • @Buttink:now that you mention it, that does seem odd... :-) – Jerry Coffin Mar 25 '10 at 21:56
  • 7
    @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++ ;-) – Steve Jessop Mar 25 '10 at 22:21
  • @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. – David Stocking Mar 26 '10 at 05:30
  • 1
    @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..." – Jerry Coffin Mar 26 '10 at 05:56
  • Not all that bad though. It's only required to care about ranges `0 .. UCHAR_MAX` or `EOF` :) – Johannes Schaub - litb Mar 28 '10 at 11:19
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.

avakar
  • 32,009
  • 9
  • 68
  • 103
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).

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
0

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

osgx
  • 90,338
  • 53
  • 357
  • 513
  • 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! :-) – Jerry Coffin Mar 25 '10 at 22:56
  • 3
    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. – Billy ONeal Mar 25 '10 at 23:01
  • @Jerry: I think the true connoisseur of boolean expressions starts with `(!!isalpha(ch)==(!!true==!!true))`, and takes it from there as the mood strikes. – Steve Jessop Mar 26 '10 at 03:46