Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > stream io in c

Reply
Thread Tools

stream io in c

 
 
Keith Thompson
Guest
Posts: n/a
 
      08-01-2008
Ron Ford <(E-Mail Removed)> writes:
> On Thu, 31 Jul 2008 16:04:13 +0530, santosh posted:
>
>> Can you spot the mistake in this printf call?
>>

>
> I think I got it:


Better.

> //mkchars.c:
>
>
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <limits.h>
>
> int main(void)
> {
> FILE *fp;
> char name[]="chars.256";
>
>
> unsigned char c;
>
>
>
> if ((fp = fopen(name, "wb")) == NULL)
> {
> printf("can't open %s\n", name);


I'd change this to:

fprintf(stderr, "can't open %s\n", name);

> return EXIT_FAILURE;
> }
> else
> {
> for (c = 0; c <= UCHAR_MAX; c ++) {


As others have pointed out, this loop never terminates. c is of type
unsigned char; it's *always" <= UCHAR_MAX, no matter what you do with
it.

> putc(c, fp);
> }
> fclose(fp);
> }
> return 0;
> }
> // gcc -o chars -std=c99 -pedantic -Wall -W mkchars4.c
>
> I created a problem for myself that I don't get. I checked that UCHAR_MAX
> was indeed 255 on my machine, but the subtitution for 255 causes this
> warning and the program to hang:
>
>
> C:\MinGW\source>gcc -o chars -std=c99 -pedantic -Wall -W mkchars3.c
> mkchars3.c: In function 'main':
> mkchars3.c:26: warning: comparison is always true due to limited range of
> data type
>
> I think I get it. 255 ++ = 0 ?


Um, no. 255++ is an error (specifically a constraint violation).

Remember, the "++" operator (prefix or postfix) does two things: it
modifies its argument, and it yields a value (either the previous
value or the modified value depending on where you put the "++").
You can't modify 255, so 255++ doesn't make any sense.

New C programmers are often fascinated by C's ++ operator. It's such
a cool and terse way to specify that you want to increment something.
But "x++" doesn't mean "x+1"; it's more complex than that. If you
want the incremented value of x without modifying x as a side effect,
just write "x+1". (And if you replace x with a constant 255,
you *can't* modify it.)

So what you're really asking is whether 255 + 1 == 0.

As stated, no, but there's a true statement hiding in there.

*If* UCHAR_MAX is 255 (as it very commonly is), and if you have an
object of type unsigned char with the value 255, then incrementing
that object will cause it to have the value 0.

For all unsigned types, arithmetic is performed in a wraparound
manner. So UINT_MAX + 1U == 0U, and ULONG_MAX + 1UL == 0UL.
Conversely, 0U - 1U == UINT_MAX.

And in many cases you still have to worry about promoitions and other
implicit conversions. For example, consider this:

#include <stdio.h>
#include <limits.h>
int main(void)
{
unsigned char c = UCHAR_MAX;
unsigned char c1 = c + 1;
int i1 = c + 1;

printf("c1 = %d\n", (int)c1);
printf("i1 = %d\n", i1);
return 0;
}

c1 gets the value 0; i1 gets the value 256. That's because, in the
expression c + 1, the value of c is implicitly promoted to int; adding
1 to an int value of 255 doesn't overflow or wrap around, it just
yields 256.

And although the initialization of c1 to c + 1 *acts* like it's adding
1 to an unsigned char value of 255, wrapping around, and yielding 0,
what really happens is that the value of c is promoted to int, the
expression c + 1 yields the int value 256, and that value is then
*converted* to unsigned char, yielding 0. The final result is the
same, but we took a detour from unsigned char to int and back to
unsigned char.

For integers, these implicit promotions only occur (and only in some
circumstances) for types narrower than int and unsigned int.

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
 
 
 
Ron Ford
Guest
Posts: n/a
 
      08-02-2008
On Fri, 01 Aug 2008 10:17:36 -0700, Keith Thompson posted:

> Ron Ford <(E-Mail Removed)> writes:


[snipped and re-ordered]

> Um, no. 255++ is an error (specifically a constraint violation).
>
> Remember, the "++" operator (prefix or postfix) does two things: it
> modifies its argument, and it yields a value (either the previous
> value or the modified value depending on where you put the "++").
> You can't modify 255, so 255++ doesn't make any sense.
>
> New C programmers are often fascinated by C's ++ operator. It's such
> a cool and terse way to specify that you want to increment something.
> But "x++" doesn't mean "x+1"; it's more complex than that. If you
> want the incremented value of x without modifying x as a side effect,
> just write "x+1". (And if you replace x with a constant 255,
> you *can't* modify it.)
>
> So what you're really asking is whether 255 + 1 == 0.
>
> As stated, no, but there's a true statement hiding in there.
>
> *If* UCHAR_MAX is 255 (as it very commonly is), and if you have an
> object of type unsigned char with the value 255, then incrementing
> that object will cause it to have the value 0.
>
> For all unsigned types, arithmetic is performed in a wraparound
> manner. So UINT_MAX + 1U == 0U, and ULONG_MAX + 1UL == 0UL.
> Conversely, 0U - 1U == UINT_MAX.
>
> And in many cases you still have to worry about promoitions and other
> implicit conversions. For example, consider this:
>
> #include <stdio.h>
> #include <limits.h>
> int main(void)
> {
> unsigned char c = UCHAR_MAX;
> unsigned char c1 = c + 1;
> int i1 = c + 1;
>
> printf("c1 = %d\n", (int)c1);
> printf("i1 = %d\n", i1);
> return 0;
> }
>
> c1 gets the value 0; i1 gets the value 256. That's because, in the
> expression c + 1, the value of c is implicitly promoted to int; adding
> 1 to an int value of 255 doesn't overflow or wrap around, it just
> yields 256.
>
> And although the initialization of c1 to c + 1 *acts* like it's adding
> 1 to an unsigned char value of 255, wrapping around, and yielding 0,
> what really happens is that the value of c is promoted to int, the
> expression c + 1 yields the int value 256, and that value is then
> *converted* to unsigned char, yielding 0. The final result is the
> same, but we took a detour from unsigned char to int and back to
> unsigned char.
>
> For integers, these implicit promotions only occur (and only in some
> circumstances) for types narrower than int and unsigned int.


I'm gonna need a little time to go through this more carefully.

> I'd change this to:
>
> fprintf(stderr, "can't open %s\n", name);
>


This change highlights the use of the second line of what I call the
goocher: the commented-out command lines. I would definitely expect
information like this to come from stderr.

//mkchars.c:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int main(void)
{
FILE *fp;
char name[]="chars.256";
int c;

if ((fp = fopen(name, "wb")) == NULL)
{
fprintf(stderr, "couldn't open %s\n", name);
return EXIT_FAILURE;
}
else
{
printf("creating %s\n", name);
for (c = 0; c <= UCHAR_MAX; c ++) {
putc(c, fp);
}
fprintf(stderr, "did open %s\n", name);
fclose(fp);
}
return 0;
}
// gcc -o chars -std=c99 -pedantic -Wall -W mkchars5.c
// chars >text55.txt 2>text56.txt

The first two commands were without the fprintf's:

C:\MinGW\source> gcc -o chars -std=c99 -pedantic -Wall -W mkchars5.c

C:\MinGW\source>chars
creating chars.256

C:\MinGW\source>gcc -o chars -std=c99 -pedantic -Wall -W mkchars5.c

C:\MinGW\source>chars
creating chars.256
did open chars.256

C:\MinGW\source>chars >text55.txt 2>text56.txt

C:\MinGW\source>


So it is that text55 has the "creating" and text56 has the "did open" line.
I like the reassurance from stderr that there was no error.

--
Unquestionably, there is progress. The average American now pays out twice
as much in taxes as he formerly got in wages. 1
H. L. Mencken
 
Reply With Quote
 
 
 
 
santosh
Guest
Posts: n/a
 
      08-02-2008
Ron Ford wrote:

<snip>

[code indentation corrected]

> //mkchars.c:
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <limits.h>
>
> int main(void)
> {
> FILE *fp;
> char name[]="chars.256";
> int c;
>
> if ((fp = fopen(name, "wb")) == NULL)
> {
> fprintf(stderr, "couldn't open %s\n", name);
> return EXIT_FAILURE;
> }
> else
> {
> printf("creating %s\n", name);
> for (c = 0; c <= UCHAR_MAX; c ++) {
> putc(c, fp);
> }
> fprintf(stderr, "did open %s\n", name);


Typically only error messages are sent to stderr. A normal program
message is usually sent to stdout.

> fclose(fp);
> }
> return 0;
> }


BTW, I notice that you seem to have just as much problem with consistent
formatting of your code that Bill C has.

If you use an editor like Vim or Emacs it will automatically do most of
the indenting for you. Inconsistent indentation and formatting makes
your code difficult to read, when as it is, reading properly indented
code is difficult enough.

<snip>

 
Reply With Quote
 
CBFalconer
Guest
Posts: n/a
 
      08-02-2008
santosh wrote:
> Ron Ford wrote:
>
> <snip>
>
>> #include <stdio.h>
>> #include <stdlib.h>
>> #include <limits.h>
>>
>> int main(void) { /* code tautened - cbf */
>> FILE *fp;
>> char name[]="chars.256";
>> int c;
>>
>> if ((fp = fopen(name, "wb")) == NULL) {
>> fprintf(stderr, "couldn't open %s\n", name);
>> return EXIT_FAILURE;
>> }
>> else {
>> printf("creating %s\n", name);
>> for (c = 0; c <= UCHAR_MAX; c ++) {
>> putc(c, fp);
>> }
>> fprintf(stderr, "did open %s\n", name);

>
> Typically only error messages are sent to stderr. A normal program
> message is usually sent to stdout.


However here he is keeping track of file statuses on stderr, so I
think the file choice is quite reasonable. It doesn't disturb the
real action, and the actual output could be to stdout.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.


 
Reply With Quote
 
santosh
Guest
Posts: n/a
 
      08-04-2008
pete wrote:

> pete wrote:
>> Nick Keighley wrote:
>>> On 31 Jul, 15:06, CBFalconer <(E-Mail Removed)> wrote:
>>>> Nick Keighleywrote:
>>>>> Ron Ford <(E-Mail Removed)> wrote:
>>>> ... snip ...
>>>>
>>>>>> I've tried some variations with this.
>>>>>> int i;
>>>>>> for (i = 0; i <= UCHAR_MAX; i++) putchar (i);
>>>>> for (i = 0; i < UCHAR_MAX; i++) putchar (i);
>>>> No, the original is correct. He wants to write out the entire
>>>> range available to the char type.
>>>
>>> yes. I was mistaken.

>>
>> The original one is an endless loop,

>
> It isn't an endless loop.


It isn't an endless loop, but it does potentially invoke undefined
behaviour if UCHAR_MAX > INT_MAX.

<snip>

 
Reply With Quote
 
CBFalconer
Guest
Posts: n/a
 
      08-04-2008
santosh wrote:
> pete wrote:
>> pete wrote:
>>>> CBFalconer <(E-Mail Removed)> wrote:
>>>>>> Ron Ford <(E-Mail Removed)> wrote:
>>>>> ... snip ...
>>>>>
>>>>>>> I've tried some variations with this.
>>>>>>> int i;
>>>>>>> for (i = 0; i <= UCHAR_MAX; i++) putchar (i);
>>>>>>
>>>>> No, the original is correct. He wants to write out the
>>>>> entire range available to the char type.
>>>
>>> The original one is an endless loop,

>>
>> It isn't an endless loop.

>
> It isn't an endless loop, but it does potentially invoke
> undefined behaviour if UCHAR_MAX > INT_MAX.


I don't believe that is allowable. == yes.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.


 
Reply With Quote
 
vippstar@gmail.com
Guest
Posts: n/a
 
      08-04-2008
On Aug 4, 11:53 pm, CBFalconer <(E-Mail Removed)> wrote:
> santosh wrote:
> > pete wrote:
> >> pete wrote:
> >>>> CBFalconer <(E-Mail Removed)> wrote:
> >>>>>> Ron Ford <(E-Mail Removed)> wrote:
> >>>>> ... snip ...

>
> >>>>>>> I've tried some variations with this.
> >>>>>>> int i;
> >>>>>>> for (i = 0; i <= UCHAR_MAX; i++) putchar (i);

>
> >>>>> No, the original is correct. He wants to write out the
> >>>>> entire range available to the char type.

>
> >>> The original one is an endless loop,

>
> >> It isn't an endless loop.

>
> > It isn't an endless loop, but it does potentially invoke
> > undefined behaviour if UCHAR_MAX > INT_MAX.

>
> I don't believe that is allowable. == yes.


It is. It's not allowable that UCHAR_MAX > UINT_MAX.
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      08-04-2008
CBFalconer <(E-Mail Removed)> writes:
> santosh wrote:
>> pete wrote:
>>> pete wrote:
>>>>> CBFalconer <(E-Mail Removed)> wrote:
>>>>>>> Ron Ford <(E-Mail Removed)> wrote:
>>>>>> ... snip ...
>>>>>>
>>>>>>>> I've tried some variations with this.
>>>>>>>> int i;
>>>>>>>> for (i = 0; i <= UCHAR_MAX; i++) putchar (i);
>>>>>>>
>>>>>> No, the original is correct. He wants to write out the
>>>>>> entire range available to the char type.
>>>>
>>>> The original one is an endless loop,
>>>
>>> It isn't an endless loop.

>>
>> It isn't an endless loop, but it does potentially invoke
>> undefined behaviour if UCHAR_MAX > INT_MAX.

>
> I don't believe that is allowable. == yes.


I believe it is.

Consider CHAR_BIT==32, sizeof(int)==1, 2's-complement, no padding
bits. Then UCHAR_MAX==2**32-1, and INT_MAX==2**31-1.

It causes problems for stdio, but (a) it's not clear that's enough to
make the (hypothetical) implementation non-conforming, and (b) even if
it is, we can assume it's freestanding.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Flash Gordon
Guest
Posts: n/a
 
      08-05-2008
Keith Thompson wrote, On 05/08/08 00:52:
> CBFalconer <(E-Mail Removed)> writes:
>> santosh wrote:
>>> pete wrote:
>>>> pete wrote:
>>>>>> CBFalconer <(E-Mail Removed)> wrote:
>>>>>>>> Ron Ford <(E-Mail Removed)> wrote:
>>>>>>> ... snip ...
>>>>>>>
>>>>>>>>> I've tried some variations with this.
>>>>>>>>> int i;
>>>>>>>>> for (i = 0; i <= UCHAR_MAX; i++) putchar (i);
>>>>>>> No, the original is correct. He wants to write out the
>>>>>>> entire range available to the char type.
>>>>> The original one is an endless loop,
>>>> It isn't an endless loop.
>>> It isn't an endless loop, but it does potentially invoke
>>> undefined behaviour if UCHAR_MAX > INT_MAX.

>> I don't believe that is allowable. == yes.

>
> I believe it is.
>
> Consider CHAR_BIT==32, sizeof(int)==1, 2's-complement, no padding
> bits. Then UCHAR_MAX==2**32-1, and INT_MAX==2**31-1.
>
> It causes problems for stdio, but (a) it's not clear that's enough to
> make the (hypothetical) implementation non-conforming,


Note that there are a lot of *real* implementations where sizeof(int)==1
and CHAR_BIT is 16 or greater (including ones where it is 32).

> and (b) even if
> it is, we can assume it's freestanding.


All the implementations I know of are freestanding but I don't know all
implementations.
--
Flash Gordon
 
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
Convert DVD with subtitle stream to DivX with same subtitle stream(selectable) malise Software 1 04-17-2007 09:15 AM
what is the different between byte stream and character stream? dolphin Java 6 03-18-2007 01:58 PM
get stream mode flags from an opened stream Alexander Korsunsky C++ 1 02-17-2007 10:38 AM
How to GET multi-word input from a *file* stream as opposed to a *console* stream? sherifffruitfly@gmail.com C++ 9 04-27-2006 04:14 PM
Doing readline in a thread from a popen4('rsync ...') stream blocks when the stream ends. Rasmusson, Lars Python 1 04-30-2004 08:10 AM



Advertisments