First C Program, Problems getting serial data

M

Michael Wojcik

Personally, I use !, and other operations that act on boolean values,
only for values that really are boolean. The strcmp() function yields
one of three possible kinds of result: <0, ==0, >0. If its name were
"strings_differ(), I'd happily write (!strings_differ(cmd, chdcheck)),
but since the name of the function doesn't indicate a boolean result,
I find it a bit confusing to treat it as if it did.

An explicit comparison, (strcmp(cmd, cmdcheck) == 0) makes it much
clearer what's actually going on.

Yes, this is largely a matter of style, and plenty of smart people
prefer the !strcmp() form.

And there's also the condition-parameter macro style:

#define CMP_STR(s1, op, s2) strcmp(s1, s2) op 0

if (CMP_STR(s1, ==, s2))

which inlines the condition operator and hides the 0. I think I
originally got this macro from Peter van der Linden, who presents it
in chapter 3 of _Expert C Programming_.

--
Michael Wojcik (e-mail address removed)

Thus, the black lie, issuing from his base throat, becomes a boomerang to
his hand, and he is hoist by his own petard, and finds himself a marked man.
-- attributed to a "small-town newspaper editor in Wisconsin"
 
K

Keith Thompson

Imprimis, this is a style matter; if someone finds an explicit mention
of TRUE or FALSE clearer than the presence or absence of a !, is that a
problem?

Yes, it's a problem. TRUE is presumably equal to 1, but *any*
non-zero value is considered true.

Consider this:

is_on = isalpha(c);
if (is_on == TRUE)

This can fail if isalpha returns a value other than 0 or 1, which it's
allowed to do.
Secundis, while I do agree with your style myself, there is one place
where you can't escape using == on boolean values without jumping
through silly hoops:

if (left_valve_open == right_valve_open)

Again, this fails if left_valve_open and right_valve_open have
differing non-zero values.

If you want to compare two boolean values for logical equality, you
can do something like this:

if (!!left_valve_open == !!right_valve_open)

The double "!" normalizes the value to 0 or 1. (A single "!" would
work, but it would be more obscure, since it would compare the
negations of the two conditions for equality.)

If you have a C99 compiler, you can use type _Bool (or bool with
"#include <stdbool.h>"), which can only take on the values 0 and 1
(unless you cheat and force a different value into a _Bool object).
 
R

Rod Pemberton

Keith Thompson said:
I agree that one is clearer than the other; I disagree about which one
it is.

Personally, I use !, and other operations that act on boolean values,
only for values that really are boolean. The strcmp() function yields
one of three possible kinds of result: <0, ==0, >0. If its name were
"strings_differ(), I'd happily write (!strings_differ(cmd, chdcheck)),
but since the name of the function doesn't indicate a boolean result,
I find it a bit confusing to treat it as if it did.

Determining if strings are equal or different is useful. However,
determining if the last compared character in one string was above (>0) or
below (<0) the last compared character in the other, is useless and heavily
dependent on the nonportable and sometimes random ordering of the character
set. Because of this, I'd posit that strcmp() is _essentially_ a boolean
function: zero equal, non-zero if different.
An explicit comparison, (strcmp(cmd, cmdcheck) == 0) makes it much
clearer what's actually going on.

Untrue. There is an entire generation of programmers who were taught not to
think in terms of 'true'. They were taught to think entirely in terms of
'false'. 'true' is thought of as 'not false' and 'false' is zero (for all
but a few languages, i.e., ADA which, IIRC, Keith has experience in...). An
if() statement is thought of as 'if(not false)' or 'if(not zero)'. Since
strcmp() returns zero for equality, if(!strcmp()) says 'if(not zero)' which
is understood to be 'true'. if(strcmp()==0), on the other hand says 'if(0
is equal to 0)'. This, of course, lacks the simplicity, elegance, and
mnemonic of 'if(not zero)'.
Yes, this is largely a matter of style, and plenty of smart people
prefer the !strcmp() form.

True. They are not programming in ADA and don't need to separate boolean
false and zero as distinct values.


Rod Pemberton
 
K

Keith Thompson

Rod Pemberton said:
Determining if strings are equal or different is useful. However,
determining if the last compared character in one string was above (>0) or
below (<0) the last compared character in the other, is useless and heavily
dependent on the nonportable and sometimes random ordering of the character
set. Because of this, I'd posit that strcmp() is _essentially_ a boolean
function: zero equal, non-zero if different.

strcmp() gives a consistent ordering of string values. Sometimes an
internally consistent ordering is all you need, for example if you
want to build a search tree.

strcmp() is not a boolean function.
Untrue. There is an entire generation of programmers who were taught not to
think in terms of 'true'. They were taught to think entirely in terms of
'false'. 'true' is thought of as 'not false' and 'false' is zero (for all
but a few languages, i.e., ADA which, IIRC, Keith has experience in...). An
if() statement is thought of as 'if(not false)' or 'if(not zero)'. Since
strcmp() returns zero for equality, if(!strcmp()) says 'if(not zero)' which
is understood to be 'true'. if(strcmp()==0), on the other hand says 'if(0
is equal to 0)'. This, of course, lacks the simplicity, elegance, and
mnemonic of 'if(not zero)'.

Yes, in C zero is false, and any non-zero value is true, so a boolean
value should be used directly as a condition, not compared for
equality to either true or false. Something like "if (b == true)" is
both dangerous and unnecessarily verbose; "if (b == false)" happens
not to be as dangerous (because there's only a single false value),
but it's just as unnecessarily verbose. They should be "if (b)" and
"if (!b)", respectively.

But that applies only when b is a boolean value. The result returned
by strcmp() is not.

If you want to define macros like
#define STR_EQ (strcmp((x), (y)) != 0)
#define STR_NE (strcmp((x), (y)) == 0)
then of course you can use them as conditions.

(Aside: I've never heard of a language called "ADA". I've programmed
in Ada. It's a name, not an acronym.)
True. They are not programming in ADA and don't need to separate boolean
false and zero as distinct values.

Which has no relevance to what we're actually discussing.

If you want to argue that it's acceptable to treat the result of
strcmp() as a boolean value (true if the arguments are unequal, false
if they're equal), that's not an entirely unreasable argument. I
don't happen to agree with it (if strcmp() were intended to be boolean
it would have a different name), but I recognize that some programmers
either value terseness over clarity, or just don't find !strcmp(x, y)
as unclear as I do. Bringing in an irrelevant argument about true and
false doesn't help your case.
 
R

regis

Rod said:
"Keith Thompson" <[email protected]> wrote in message
Determining if strings are equal or different is useful. However,
determining if the last compared character in one string was above (>0) or
below (<0) the last compared character in the other, is useless and heavily
dependent on the nonportable and sometimes random ordering of the character
set. Because of this, I'd posit that strcmp() is _essentially_ a boolean
function: zero equal, non-zero if different.

It is a comparison function designed to work with qsort().

If one want to easily detect multiple occurrences of strings
in an array, one way is to use qsort() along with strcmp()
so that these occurrences become contiguous,
and then any behavior of strcmp() fits the job
as long as it is a comparison function.
 
K

Keith Thompson

regis said:
It is a comparison function designed to work with qsort().

If one want to easily detect multiple occurrences of strings
in an array, one way is to use qsort() along with strcmp()
so that these occurrences become contiguous,
and then any behavior of strcmp() fits the job
as long as it is a comparison function.

I'm sure strcmp() was intended to be used directly with qsort() when
the functions were originally designed. However, qsort() expects a
comparison function that takes two arguments of type "const void*",
whereas strcmp() expects arguments of type "const char*". There are
some guarantees of compatibility between void* and char*, but I'm not
sure they extend to compatbility of functions taking them as
arguments.

At worst, though, strcmp() can be used with qsort() with a very simple
wrapper.
 
K

Kenneth Brody

Rod Pemberton wrote:
[...]
Determining if strings are equal or different is useful. However,
determining if the last compared character in one string was above (>0) or
below (<0) the last compared character in the other, is useless

I'm sure anyone who has needed to sort a list of strings will disagree
with your "useless" tag.
and heavily
dependent on the nonportable and sometimes random ordering of the character
set.

Yet it will always compare the same way on a given platform.

And if you're on a platform where the letters do not sort in order, then
you get what you deserve. :)
Because of this, I'd posit that strcmp() is _essentially_ a boolean
function: zero equal, non-zero if different.

Hardly.

While that _might_ be the _majority_ of the cases where it's used, it's
hardly the only way.
Untrue. There is an entire generation of programmers who were taught not to
think in terms of 'true'. They were taught to think entirely in terms of
'false'. 'true' is thought of as 'not false' and 'false' is zero (for all
but a few languages, i.e., ADA which, IIRC, Keith has experience in...). An
if() statement is thought of as 'if(not false)' or 'if(not zero)'. Since
strcmp() returns zero for equality, if(!strcmp()) says 'if(not zero)' which
is understood to be 'true'. if(strcmp()==0), on the other hand says 'if(0
is equal to 0)'. This, of course, lacks the simplicity, elegance, and
mnemonic of 'if(not zero)'.

But, as has been pointed out, strcmp() _isn't_ a boolean function. And
if you treat it as if it were, the "truthness" is backwards from how most
people would think of it. If you are comparing two strings, "true" should
mean "equal". By testing "if (!strcmp(a,b))", most people would probably
read it as "if the two strings are _not_ equal".

[...]

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
R

Rod Pemberton

Keith Thompson said:
strcmp() gives a consistent ordering of string values. Sometimes an
internally consistent ordering is all you need, for example if you
want to build a search tree.

strcmp() is not a boolean function.

I never said it was. I said it is _essentially_ a boolean function. That's
because ordering of string values is a very low use situation...
Yes, in C zero is false, and any non-zero value is true, so a boolean
value should be used directly as a condition, not compared for
equality to either true or false. Something like "if (b == true)" is
both dangerous and unnecessarily verbose; "if (b == false)" happens
not to be as dangerous (because there's only a single false value),
but it's just as unnecessarily verbose. They should be "if (b)" and
"if (!b)", respectively.

But that applies only when b is a boolean value. The result returned
by strcmp() is not.


(Aside: I've never heard of a language called "ADA". I've programmed
in Ada. It's a name, not an acronym.)

True enough, although it is frequently found all capitalized.
Which has no relevance to what we're actually discussing.

Yes, it does. That is where you're perspective originates and is why you
have 'clarity' issues with treating the result of strcmp as a boolean.
If you want to argue that it's acceptable to treat the result of
strcmp() as a boolean value (true if the arguments are unequal, false
if they're equal), that's not an entirely unreasable argument. I
don't happen to agree with it (if strcmp() were intended to be boolean
it would have a different name), but I recognize that some programmers
either value terseness over clarity, or just don't find !strcmp(x, y)
as unclear as I do.
just don't find !strcmp(x, y) as unclear as I do.

Why do you find this unclear? If you treat 1 and -1 as 'not false' and 0 as
false, it's completely clear.
Bringing in an irrelevant argument about true and
false doesn't help your case.

Irrelevant? I tried to explain things, when _you_ said you found things
unclear:

The discussion regarding true and false describes why others don't find it
unclear. If you spent time to comprehend, perhaps it would help your
clarity.


Rod Pemberton
 
K

Keith Thompson

Rod Pemberton said:
The discussion regarding true and false describes why others don't find it
unclear. If you spent time to comprehend, perhaps it would help your
clarity.

I understand your argument. I just disagree with it.
 
F

Flash Gordon

Rod said:
Keith Thompson said:
Rod Pemberton said:
news:[email protected]... [...]
Personally, I use !, and other operations that act on boolean values,
only for values that really are boolean. The strcmp() function yields
one of three possible kinds of result: <0, ==0, >0. If its name were
"strings_differ(), I'd happily write (!strings_differ(cmd, chdcheck)),
but since the name of the function doesn't indicate a boolean result,
I find it a bit confusing to treat it as if it did.
Determining if strings are equal or different is useful. However,
determining if the last compared character in one string was above (>0) or
below (<0) the last compared character in the other, is useless and heavily
dependent on the nonportable and sometimes random ordering of the character
set. Because of this, I'd posit that strcmp() is _essentially_ a boolean
function: zero equal, non-zero if different.
strcmp() gives a consistent ordering of string values. Sometimes an
internally consistent ordering is all you need, for example if you
want to build a search tree.

strcmp() is not a boolean function.

I never said it was. I said it is _essentially_ a boolean function. That's
because ordering of string values is a very low use situation...

No, it is essentially a comparison function with three return values,
something I have a lot of use for. It is often used in a boolean context
where two of those values are treated the same.
True enough, although it is frequently found all capitalized.

That doesn't make it correct.
Yes, it does. That is where you're perspective originates and is why you
have 'clarity' issues with treating the result of strcmp as a boolean.

I spent a lot of my early career as an assembler programmer, and
comparing strings I would naturally end up with something that behaved
like strcmp since comparing two bytes gave that information on the
processors I was using. So I come from a background of not having a boolean.

Like Keith I find it easier to read/write comparing strcmp with 0 than
using it as a boolean. I can read it used as a boolean, I just have to
spend an extra couple of seconds interpreting it.
Why do you find this unclear? If you treat 1 and -1 as 'not false' and 0 as
false, it's completely clear.

It is unambiguous but for some it takes longer to read than a comparison
with 0.
Irrelevant? I tried to explain things, when _you_ said you found things
unclear:

Some people find that reading "if (strcmp(x,y))" or "if (!strcmp(x,y))"
takes a little though where comparing against 0 doesn't because they
think of it as returning three values, not returning a boolean that is
the wrong way up.
The discussion regarding true and false describes why others don't find it
unclear. If you spent time to comprehend, perhaps it would help your
clarity.

I'm sure Keith fully understands how boolean context work in C.
 
R

regis

Keith said:
I'm sure strcmp() was intended to be used directly with qsort() when
the functions were originally designed. However, qsort() expects a
comparison function that takes two arguments of type "const void*",
whereas strcmp() expects arguments of type "const char*". There are
some guarantees of compatibility between void* and char*, but I'm not
sure they extend to compatbility of functions taking them as
arguments.

At worst, though, strcmp() can be used with qsort() with a very simple
wrapper.

Oups. And to make things worse...

Should this extension of compatibility have existed between
functions taking "char*" and "void*" as arguments,
this would not have worked either with the example I had in mind,
that is, sorting an array of elements, each of type char *,
because another level of indirection is introduced:

The comparison function of qsort expects two pointers to the elements
be compared, as opposed to the elements themselves,
therefore here, behind the two "void *"
it expects two "const char **" as opposed to two "const char *"

int strcmp_wrapper (const void * a, const void * b)
{
return strcmp (* (const char **) a, * (const char **) b);
}
 
B

Barry Schwarz

It is a comparison function designed to work with qsort().

strcmp is not designed to work with qsort. Passing strcmp to qsort as
the fourth parameter requires a diagnostic.


Remove del for email
 
R

Richard Bos

Rod Pemberton said:
I never said it was. I said it is _essentially_ a boolean function. That's
because ordering of string values is a very low use situation...

Speaking as someone who has dealt with databases containing names, I
have to snigger a bit at your naivete.
True enough, although it is frequently found all capitalized.

So? main() is also frequently declared void. Red lights are frequently
driven through.

Richard
 
R

Richard Bos

Keith Thompson said:
Yes, it's a problem. TRUE is presumably equal to 1, but *any*
non-zero value is considered true.

Consider this:

is_on = isalpha(c);
if (is_on == TRUE)

This can fail if isalpha returns a value other than 0 or 1, which it's
allowed to do.


Again, this fails if left_valve_open and right_valve_open have
differing non-zero values.

Yes and yes, but then you're not talking about truly boolean values in
the first place.

Richard
 
K

Keith Thompson

Keith Thompson said:
(e-mail address removed) (Richard Bos) writes: [...]
Imprimis, this is a style matter; if someone finds an explicit mention
of TRUE or FALSE clearer than the presence or absence of a !, is that a
problem?

Yes, it's a problem. TRUE is presumably equal to 1, but *any*
non-zero value is considered true.

Consider this:

is_on = isalpha(c);
if (is_on == TRUE)

This can fail if isalpha returns a value other than 0 or 1, which it's
allowed to do.
Secundis, while I do agree with your style myself, there is one place
where you can't escape using == on boolean values without jumping
through silly hoops:

if (left_valve_open == right_valve_open)

Again, this fails if left_valve_open and right_valve_open have
differing non-zero values.

Yes and yes, but then you're not talking about truly boolean values in
the first place.

What do you mean by "truly boolean values"? Prior to C99's
introduction of _Bool, C had no such concept.

Unless they're declared as _Bool, it's a bad idea to assume that
left_valve_open and right_valve_open can only take on the values
0 and 1. Even if you carefully design your program to use only 0 and
1, there's always the risk that you (or a future maintainer) will
introduce a call to isalpha() or something similar. The resulting bug
could be very hard to track down.
 
S

Simon Biber

regis said:
Oups. And to make things worse...

Should this extension of compatibility have existed between
functions taking "char*" and "void*" as arguments,
this would not have worked either with the example I had in mind,
that is, sorting an array of elements, each of type char *,
because another level of indirection is introduced:

The comparison function of qsort expects two pointers to the elements
be compared, as opposed to the elements themselves,
therefore here, behind the two "void *"
it expects two "const char **" as opposed to two "const char *"

int strcmp_wrapper (const void * a, const void * b)
{
return strcmp (* (const char **) a, * (const char **) b);
}

This function is badly named, it extends into the name space reserved
for extensions. In general, try not to start functions with 'str'.

You are also casting to the wrong type. The const is in the wrong
location, so you are actually casting away the const qualifier in the
original type.

When programming, I always try to avoid casts whenever possible:

#include <string.h>

int wrap_strcmp(const void * a, const void * b)
{
char * const * c = a;
char * const * d = b;
return strcmp(*c, *d);
}

Although this uses two extra temporary variables, I find the lack of
casts to be an important indicator that there is less likely to be an
erroneous conversion (such as yours).

Simon.
 
R

regis

Simon said:
regis wrote:

This function is badly named, it extends into the name space reserved
for extensions. In general, try not to start functions with 'str'.

You are also casting to the wrong type. The const is in the wrong
location, so you are actually casting away the const qualifier in the
original type.

When programming, I always try to avoid casts whenever possible:

#include <string.h>

int wrap_strcmp(const void * a, const void * b)
{
char * const * c = a;
char * const * d = b;
return strcmp(*c, *d);
}

Although this uses two extra temporary variables, I find the lack of
casts to be an important indicator that there is less likely to be an
erroneous conversion (such as yours).

Thank you for the correction.
If I had used the two temporary without cast, my compiler
would have warned me about the misplaced const qualifier.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,183
Messages
2,570,965
Members
47,511
Latest member
svareza

Latest Threads

Top