Is there a chance that something bad might happen here? Thanks.Code:char c = 'A'; c = tolower(c);
Is there a chance that something bad might happen here? Thanks.Code:char c = 'A'; c = tolower(c);
tolower and the other character functions expect an int which is representable as an unsigned char and you are passing a char, which may be signed, depending on your compiler and options. Therefore, it is a good idea to use a cast with these functions:
Other than that, your code is fine. It is acceptable to use a variable twice in a statement. What is not acceptable, is to modify it twice. This would produce undefined behaviour:Code:c = tolower( (unsigned char) c);
Code:c = tolower( (unsigned char) c++);
Actually, the second should be very defined. c is incremented AFTER it is passed to tolower, BEFORE it is assigned the value returned from tolower.
Free code: http://sol-biotech.com/code/.
It is not that old programmers are any smarter or code better, it is just that they have made the same stupid mistake so many times that it is second nature to fix it.
--Me, I just made it up
The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man.
--George Bernard Shaw
Yep, my mistake, there is a sequence point before the function call. I was thinking of the assigment, which is not a sequence point.Originally Posted by mitakeet
Take 2. This is bad:C89 Draft
The following are the sequence points described in 2.1.2.3
* The call to a function, after the arguments have been evaluated (3.3.2.2).
* The end of the first operand of the following operators: logical AND && (3.3.13); logical OR || (3.3.14); conditional ? (3.3.15); comma , (3.3.17).
* The end of a full expression: an initializer (3.5.7); the expression in an expression statement (3.6.3); the controlling expression of a selection statement ( if or switch ) (3.6.4); the controlling expression of a while or do statement (3.6.5); the three expressions of a for statement (3.6.5.3); the expression in a return statement (3.6.6.4).
Code:c = tolower( (unsigned char) c) + c++;
Or perhaps just:Code:c = c++;
If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein
that should however be the same as c=c;c++;Originally Posted by pianorain
>that should however be the same as c=c;c++;
But it isn't. The expression is undefined because it modifies c more than once between sequence points.
My best code is written with the delete key.
The cast is useless. All values of an unsigned character will fit in an integer. You can pass it a negative value, it just doesn't have to do anything with it.
Quzah.
Hope is the first step on the road to disappointment.
Using a cast is strongly recommended*. If you pass a negative value (and not EOF) to one of the ctype functions, the behaviour is undefined:Originally Posted by Quzah
This is not a theoretical issue. Some modern C libraries will crash or give the wrong result without the cast.Originally Posted by C Standard
*Although, in this specific case 'A' is guaranteed to be positive, so it's not needed.
http://cboard.cprogramming.com/showthread.php?p=427882
http://groups-beta.google.com/group/...a8ff53f0?hl=en
http://www.greenend.org.uk/rjk/2001/02/cfu.html
http://www.stanford.edu/~blp/writing...type-cast.html
http://groups-beta.google.com/group/...94bd62676bcf91
http://groups-beta.google.com/group/...b4b76ac886b3ff
http://www.cs.mu.oz.au/research/merc...9807/0309.html
[offtopic]Originally Posted by Prelude
Why don't schools teach students about sequence points? I've never heard it mentioned in any CS syllabus. It wasn't until certain individuals here at CBoard kept banging sequence points into my head that I finally got it. It seems pretty important to know, since a lack of knowledge can lead to creating code that results in undefined expressions.
[/offtopic]
If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein
>Why don't schools teach students about sequence points?
Because sequence points are "advanced trivia" and only required knowledge if you want to understand the language. Schools only want you to memorize their bad habits, not understand enough to correct them in public. Have you ever seen how we jump on people claiming to be teachers? That's what schools try to avoid in the classroom.
My best code is written with the delete key.
It's still pointless. Why mung up your data just so it fits what the function handles? Pass it the right value in the first place, and don't waste your time on pointless casts.Originally Posted by anonytmouse
[edit]
Here, let me further the point of why your cast is not only pointless, it's wrong. Read me. Now do you see why your cast is not only pointless, it's wrong to do so? If not, read that again.
However, if you insist, here is the "correct wrong way" to do it:
Why? Because the function doesn't want an unsigned char. It wants an integer. So if you're going to be "correct" in your wrongness, it's only fitting that you typecast it back to an int. After all, that's what the function wants.Code:toupper( (int)((unsigned char) x) );
Don't you just hate being wrong?
[/edit]
Quzah.
Last edited by quzah; 06-28-2005 at 09:33 PM.
Hope is the first step on the road to disappointment.
Well, Athabasca University still uses void main() in their assignments, as of 2005 :-/Originally Posted by pianorain
I was a little surprised to see that was the case, but there you go. I guess the teachers don't know everything after all
James G. Flewelling
Rgistered Linux User #327359
Athabasca University Student (BSc. CIS)
http://catb.org/~esr/faqs/smart-questions.html
http://catb.org/jargon/
http://www.ebb.org/ungeek
---GEEK CODE---
Version: 3.12
GCS/IT/M d- s+:++ a-->->>+>++>+++>? C++++>$ UL++>++++$ P++>++++ L++>++++$
E W++ N o? K? w++(--)>--- O? M? V? PS--(---) PE Y+ PGP? t 5? !X R(*)>++
tv-->! b++(+++)>++++ DI? D+++(---)>++++$ G e*>++$ h++>*$ r!>+++ y?
----/GEEK CODE----
upd: 2005-02-11
Here are some implementations of ctype functions from the compilers I have installed on my machine.Originally Posted by Quzah
Code:extern unsigned char _ctype[]; #define isalpha(c) ((_ctype+1)[c]&(_UPPER|_LOWER)) #define isupper(c) ((_ctype+1)[c]&_UPPER) #define islower(c) ((_ctype+1)[c]&_LOWER) #define isdigit(c) ((_ctype+1)[c]&_DIGIT)Code:extern const unsigned short *_pctype; #define __chvalidchk(a,b) (_pctype[a] & (b)) #define isalpha(_c) (MB_CUR_MAX > 1 ? _isctype(_c,_ALPHA) : __chvalidchk(_c, _ALPHA)) #define isupper(_c) (MB_CUR_MAX > 1 ? _isctype(_c,_UPPER) : __chvalidchk(_c, _UPPER)) #define islower(_c) (MB_CUR_MAX > 1 ? _isctype(_c,_LOWER) : __chvalidchk(_c, _LOWER))Do you see why the cast is needed yet? Negative character values are valid in many locales.Code:/* According to standard for SB chars, these function are defined only * for input values representable by unsigned char or EOF. * Thus, there is no range test. */ unsigned short* _pctype; #define __ISCTYPE(c, mask) (MB_CUR_MAX == 1 ? (_pctype[c] & mask) : _isctype(c, mask)) extern __inline__ int isalnum(int c) {return __ISCTYPE(c, (_ALPHA|_DIGIT));} extern __inline__ int isalpha(int c) {return __ISCTYPE(c, _ALPHA);} extern __inline__ int iscntrl(int c) {return __ISCTYPE(c, _CONTROL);}
Good thread on the issue.
Previous debate on the issue.
Apache wrapper macros.
wGet wrapper macros
/* OK, now define a decent interface to ctype macros. The regular
ones misfire when you feed them chars >= 127, as they understand
them as "negative", which results in out-of-bound access at
table-lookup, yielding random results. This is, of course, totally
bogus. One way to "solve" this is to use `unsigned char'
everywhere, but it is nearly impossible to do that cleanly, because
all of the library functions and system calls accept `char'.
Thus we define our wrapper macros which simply cast the argument to
unsigned char before passing it to the <ctype.h> macro. These
versions are used consistently across the code. */
#define ISASCII(x) isascii ((unsigned char)(x))
#define ISALPHA(x) isalpha ((unsigned char)(x))
#define ISSPACE(x) isspace ((unsigned char)(x))
#define ISDIGIT(x) isdigit ((unsigned char)(x))
#define ISXDIGIT(x) isxdigit ((unsigned char)(x))
Last edited by anonytmouse; 06-29-2005 at 11:43 AM.
Do you see why the cast is wrong? No? Go read the EOF FAQ again then.
Quzah.
Hope is the first step on the road to disappointment.