Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > condition true or false? -> (-1 < sizeof("test"))

Reply
Thread Tools

condition true or false? -> (-1 < sizeof("test"))

 
 
John Reye
Guest
Posts: n/a
 
      05-17-2012
Hello,

please can someone explain why
(-1 < sizeof("test"))
is false.

What do you think the following will print?

/***********************/
#include <stdio.h>

int main(void)
{
int i;

if (-1 < sizeof("test1")) {
printf("Cool line 1\n");
}

if (-1 < -1 + sizeof("test2")) {
printf("Cool line 2\n");
}

for (i = -1; i >= -3; i--) {
if (i < i + 1U) {
printf("Here %d\n", i);
}
}
return 0;
}




I am truly shocked and amazed.

Is there any coding suggestion that will (in future) save me half an
hour of sprinkling printf's like wild and thinking my compiler is
buggy, and that logic has just died?!!!!!!

What do I need to know to avoid these surprises and is there some
"coding style" that can guard against it.

Thanks!




For the real-world code, that caused my confusion:
#include <stdio.h>
#include <limits.h>

#if EOF != -1
#error EOF is not -1
#endif

int arr[UCHAR_MAX+2]; // storage for every unsigned char, and one
additional value

#define NUM_ARRAY_ELEMENTS(arr) (sizeof(arr)/sizeof(arr[0]))

int main(void)
{
int i;
for (i = EOF; i < EOF + NUM_ARRAY_ELEMENTS(arr); i++) {
printf("%d\n", i);
arr[i+1] = i;
}
return 0;
}
 
Reply With Quote
 
 
 
 
John Reye
Guest
Posts: n/a
 
      05-17-2012
For some more (similar) surprises:

#include <stdio.h>

int main(void)
{
int i;
char arr[1000];

if (-5 < sizeof(arr))
printf("Will this print?\n");

if (-99999999999999999 < sizeof(arr))
printf("What about this?\n");

return 0;
}
 
Reply With Quote
 
 
 
 
BartC
Guest
Posts: n/a
 
      05-17-2012
"Robert Wessel" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> On Thu, 17 May 2012 01:40:08 -0700 (PDT), John Reye
> <(E-Mail Removed)> wrote:


>>please can someone explain why
>> (-1 < sizeof("test"))
>>is false.


> Somewhat simplified*, C's "usual arithmetic conversions" convert
> signed integers to unsigned when paired with an unsigned value for
> some operator.


> As to coding techniques... Don't compare signed and unsigned numbers
> unless you really mean it. Your compiler should flag that sort of
> thing at higher warning levels.


I always thought C was really a multitude of languages, not one, when the
myriad compiler options are taken into accounts.

Having one module allow mixed arithmetic, and not another, is a good
example. (Someone else uses a different compiler and different switches, and
different things will happen.)

MSVC will flag that sort of thing at
> -W2 and above (and there a way to turn on that specific warning even
> at -W1). In any event, you should really be using -W3 (assuming MSVC)
> as a minimum anyway (-W4 can be somewhat painful). For GCC, turn on
> "-Wconversion", which, I think, gets turn on with "-Wall".


-Wall doesn't seem to turn on -Wconversion.

However, -Wconversion doesn't give a warning in this example:

unsigned int a=4;
signed int b=-2;

printf("%u<%d = %d\n\n", a, b, a<b);
printf("%d<%d = %d\n\n", 4, b, 4<b);
printf("%u<%d = %d\n\n", a, -2, a<-2);
printf("%d<%d = %d\n\n", 4, -2, 4<-2);

which gives conflicting results. (Presumably an integer literal such as "4"
is assumed to be signed? Having it as unsigned would be more intuitive, as
it would be impossible for it to be negative.)

--
Bartc

 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      05-17-2012
"BartC" <(E-Mail Removed)> writes:

> "Robert Wessel" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed)...
>> On Thu, 17 May 2012 01:40:08 -0700 (PDT), John Reye
>> <(E-Mail Removed)> wrote:

>
>>>please can someone explain why
>>> (-1 < sizeof("test"))
>>>is false.

>
>> Somewhat simplified*, C's "usual arithmetic conversions" convert
>> signed integers to unsigned when paired with an unsigned value for
>> some operator.

>
>> As to coding techniques... Don't compare signed and unsigned numbers
>> unless you really mean it. Your compiler should flag that sort of
>> thing at higher warning levels.

>
> I always thought C was really a multitude of languages, not one, when the
> myriad compiler options are taken into accounts.
>
> Having one module allow mixed arithmetic, and not another, is a good
> example. (Someone else uses a different compiler and different switches, and
> different things will happen.)


That's an odd way to look at it. Mixed arithmetic is always allowed. I
don't regard the presence of more or fewer warnings as indicating that I
am using a different language!

<snip>
> (Presumably an integer literal such as "4"
> is assumed to be signed? Having it as unsigned would be more intuitive, as
> it would be impossible for it to be negative.)


But that would turn x < 4 into an unsigned comparison. Worse, -1 would
always be unsigned (and large). You'd need to alter a lot of details if
you change something as fundamental as the type of a literal constant.

--
Ben.
 
Reply With Quote
 
gwowen
Guest
Posts: n/a
 
      05-17-2012
On May 17, 9:40*am, John Reye <(E-Mail Removed)> wrote:

> I am truly shocked and amazed.


Utterly horrible isn't it? A bizarre misfeature.

> Is there any coding suggestion that will (in future) save me half an
> hour of sprinkling printf's like wild and thinking my compiler is
> buggy, and that logic has just died?!!!!!!
>
> What do I need to know to avoid these surprises and is there some
> "coding style" that can guard against it.


All I can suggest is to turn the compiler warnings on to the
absolutely highest possible, and understand why they warn. Compiled
with

gcc -Wall -Wextra -Werror

for example, the above code will fail to compile and the diagnostic
will be something like:

"Error: comparison between signed and unsigned types"

It'll also flag things like
if(x = 1){
...
}

where you (probably) meant

if(x==1){
...
}

and tell you what to do if you *meant* if(x=1)...
 
Reply With Quote
 
Andreas Perstinger
Guest
Posts: n/a
 
      05-17-2012
On 2012-05-17 12:16, BartC wrote:
> However, -Wconversion doesn't give a warning in this example:


You need -Wsign-compare (or -Wextra) with gcc in your example.

> unsigned int a=4;
> signed int b=-2;
>
> printf("%u<%d = %d\n\n", a, b, a<b);
> printf("%d<%d = %d\n\n", 4, b, 4<b);
> printf("%u<%d = %d\n\n", a, -2, a<-2);
> printf("%d<%d = %d\n\n", 4, -2, 4<-2);
>
> which gives conflicting results.


Why are the results conflicting?

1) a < b: you are comparing unsigned int and signed int -> signed int
gets converted to unsigned -> 4 is smaller than -2 + UMAX_INT + 1

2) 4 < b: your are comparing a decimal integer constant (which is
normally of type signed int) with signed int -> no implicit conversion
-> 4 isn't smaller than -2

3) a < -2: you are comparing unsigned int with a decimal integer
constant (type signed int) -> -2 is converted to unsigned int -> 4 is
smaller than -2 + UMAX_INT + 1

4) 4 < -2: you are comparing a decimal integer constant with another
decimal integer constant -> no implicit conversion -> 4 isn't smaller
than -2

I think your problem is that in example 1 and 3 you print the signed
values (b and -2) with the %d format specifier but to see what's going
on you have to use %u because they get converted to unsigned int before
the comparison is evaluated:

printf("%u<%u = %d\n\n", a, b, a<b);
printf("%d<%d = %d\n\n", 4, b, 4<b);
printf("%u<%u = %d\n\n", a, -2, a<-2);
printf("%d<%d = %d\n\n", 4, -2, 4<-2);

Bye, Andreas
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      05-17-2012
On 5/17/2012 4:40 AM, John Reye wrote:
> Hello,
>
> please can someone explain why
> (-1< sizeof("test"))
> is false.


Because of the "usual arithmetic conversions," 6.3.1.8.
Most arithmetic operators require operands of the same type,
so for differing types the UAC's operate to reconcile them
before the operation is performed. In this case you have an
int and a size_t, and the UAC's convert the int to size_t:

if ( (size_t)-1 < sizeof("test") )

Since size_t is an unsigned type, (size_t)-1 is the largest
value the type can represent, and is a good deal greater
than (size_t)5.

Aside: I suppose that on a perverse implementation the
outcome might be different. If (size_t)-1 is mathematically
no greater than INT_MAX the conversion would go the other way.
The size_t would convert to an int before the comparison and
you'd have:

if ( -1 < (int)sizeof("test") )

I've never heard of an implementation where size_t is so
narrow, and I'm not 100% sure it would be conforming -- but
I'm not 100% sure it would be forbidden, either.

> Is there any coding suggestion that will (in future) save me half an
> hour of sprinkling printf's like wild and thinking my compiler is
> buggy, and that logic has just died?!!!!!!
>
> What do I need to know to avoid these surprises and is there some
> "coding style" that can guard against it.


Try cranking up the warning levels on your compiler. If
you use gcc, "-W -Wall" will produce warnings for comparisons
between signed and unsigned types (there's surely a more specific
"-Wsomething" for just that particular warning, but I can't be
bothered to go ferret out just what it is).

--
Eric Sosman
http://www.velocityreviews.com/forums/(E-Mail Removed)d
 
Reply With Quote
 
BartC
Guest
Posts: n/a
 
      05-17-2012


"Andreas Perstinger" <(E-Mail Removed)> wrote in message
news:jp2nkq$36f$(E-Mail Removed)...
> On 2012-05-17 12:16, BartC wrote:
> > However, -Wconversion doesn't give a warning in this example:

>
> You need -Wsign-compare (or -Wextra) with gcc in your example.
>
> > unsigned int a=4;
> > signed int b=-2;
> >
> > printf("%u<%d = %d\n\n", a, b, a<b);


> > which gives conflicting results.

>
> Why are the results conflicting?
>
> 1) a < b: you are comparing unsigned int and signed int -> signed int
> gets converted to unsigned -> 4 is smaller than -2 + UMAX_INT + 1


> I think your problem is that in example 1 and 3 you print the signed
> values (b and -2) with the %d format specifier but to see what's going


Because they are signed!

> on you have to use %u because they get converted to unsigned int before
> the comparison is evaluated:
>
> printf("%u<%u = %d\n\n", a, b, a<b);


This is the point. You're just demonstrating here *how* it manages to print
the wrong result!

But the fact is that b *is* signed, and needs to be displayed with %d. So in
my original example, the 4 and -2 were printed correctly in each case.

Also my gcc didn't give any warnings despite using -Wconversion.

--
Bartc

 
Reply With Quote
 
BartC
Guest
Posts: n/a
 
      05-17-2012
"Ben Bacarisse" <(E-Mail Removed)> wrote in message
news:0.893910e519ad620c6915.20120517122826BST.87vc (E-Mail Removed)...
> "BartC" <(E-Mail Removed)> writes:


>> (Presumably an integer literal such as "4"
>> is assumed to be signed? Having it as unsigned would be more intuitive,
>> as
>> it would be impossible for it to be negative.)

>
> But that would turn x < 4 into an unsigned comparison. Worse, -1 would
> always be unsigned (and large).


1 would be unsigned.

-1, assuming constant folding by the compiler, would be equivalent to a
signed integer literal of "-1".

(If not, then it remains the negation of unsigned 1, performed at runtime.
For this purpose, negating an unsigned value would need to be allowed, and I
can't see a problem with that, except the usual overflow issues).

--
Bartc



 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      05-17-2012
On 5/17/2012 6:16 AM, BartC wrote:
>
> I always thought C was really a multitude of languages, not one, when the
> myriad compiler options are taken into accounts.


Not a multitude of languages, but a multitude of implementations.
Changing the compiler options is equivalent to changing the compiler.
The Standard is silent on whether different implementations must
interoperate smoothly, but the compiler's documentation should tell
you which sets of flags are and are not compatible. (For example,
it might be impossible to mix "-ILP32" and "-LP64" modules in the
same executable, even if "the same" compiler generates both.)

> which gives conflicting results. (Presumably an integer literal such as "4"
> is assumed to be signed? Having it as unsigned would be more intuitive, as
> it would be impossible for it to be negative.)


Well, "4" is not an integer literal, but that's a markup issue

The types of integer constants depend on their magnitude and
on the notation used, as described in 6.4.4.1p5. The constant 4
has type int, and is signed even though the value is positive.
If you think it would be "more intuitive" for the 4 to be unsigned,
please ponder `-8 / 4' and `-8 / 4u' and explain why having them
be identical would be unsurprising.

--
Eric Sosman
(E-Mail Removed)d
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Help with while condition OR condition Bill W. Ruby 13 05-09-2011 09:42 PM
[False,True] and [True,True] --> [True, True]????? bdb112 Python 45 04-29-2009 02:35 AM
Loop until condition is true Remi Villatel Python 40 06-23-2005 07:21 PM
Condition outside loop or separate loop for different condition? - Java 12 06-15-2005 08:50 AM
Why is this condition true when it should be false ? Zenobia ASP .Net 0 07-08-2004 07:54 AM



Advertisments