I think this is an impossible assignment...could you help?

K

Keith Thompson

Joe Pfeiffer said:
What in it requires non-portable C?

It could be implemented on top of some other input routine, but
eventually *something* has to perform some system-specific action to
perform the actual input (such as calling read(), for example).
 
J

Joe Pfeiffer

Keith Thompson said:
Joe Pfeiffer said:
Keith Thompson said:
[...]
scanf() doesn't happen to be one of those functions; the required
behavior for scanf() can be implemented entirely in C code that calls
other C standard library functions, without using any of the other
members of the scanf() family. But if your argument were valid, it would
also apply to fgetc().

Actually, I was unaware that fgetc() had any non-C code in it -- what
does it do that requires assembler?

fgetc() cannot be written in *portable* C.

What in it requires non-portable C?

It could be implemented on top of some other input routine, but
eventually *something* has to perform some system-specific action to
perform the actual input (such as calling read(), for example).

Well, sure, but by that definition his assignment really is impossible,
since it calls for him to get input from stdin.
 
E

Eric Sosman

[...]
Also, 0x8000000 might be valid long on some systems, but that's not
guaranteed.

0x8000000 *is* a valid long, on *all* systems. (But the
original's 0x80000000 count-the-zeroes-carefully might not be.)
 
E

Eric Sosman

[...]
fgetc() cannot be written in *portable* C.

#include <stdio.h>
int fgetc(FILE *stream) {
return getc(stream);
}

You may object that this isn't "portable" because it relies on
the knowledge that getc() doesn't call fgetc(), knowledge that the
implementation has but a portable user program lacks. But then, no
portable user program can implement fgetc() at all, nor strlen() nor
sqrt() nor anything else in the Standard library: They all belong to
the implementation, so any attempt to implement them in portable C
is doomed from the word "Go."
 
J

James Kuyper

Keith Thompson said:
Joe Pfeiffer said:
[...]
scanf() doesn't happen to be one of those functions; the required
behavior for scanf() can be implemented entirely in C code that calls
other C standard library functions, without using any of the other
members of the scanf() family. But if your argument were valid, it would
also apply to fgetc().

Actually, I was unaware that fgetc() had any non-C code in it -- what
does it do that requires assembler?

fgetc() cannot be written in *portable* C.

What in it requires non-portable C?

It could be implemented on top of some other input routine, but
eventually *something* has to perform some system-specific action to
perform the actual input (such as calling read(), for example).

Well, sure, but by that definition his assignment really is impossible,
since it calls for him to get input from stdin.

The problem statement specifically allows scan_int() to call getchar(),
which is sufficient to achieve the specified goal.

I was making the distinction between scanf(), which can be implemented
entirely in terms of calls to lower level C standard library functions,
and fgetc(), which cannot. Your argument that scan_int() could be
implemented in C, since scanf() was implemented in C, didn't make that
distinction.

Your conclusion was basically correct, but reaching that conclusion can
be justified only by careful examination of the specification of scanf()
and a comparison with the restrictions imposed on the implementation of
scan_int(). Such an analysis leads to the conclusion that it's not
possible for x = scan_int() to match the locale-dependence of the
behavior of scanf("%d",&x), since calls to isspace() are prohibited, but
the assignment is otherwise feasible.
 
J

James Kuyper

[...]
fgetc() cannot be written in *portable* C.

#include <stdio.h>
int fgetc(FILE *stream) {
return getc(stream);
}

You may object that this isn't "portable" because it relies on
the knowledge that getc() doesn't call fgetc(), knowledge that the
implementation has but a portable user program lacks.

No, the real problem is that it just pushes the issue off to getc().
Whether fgetc() calls getc(), or vice versa, one of them actually has to
read a character from a storage device, and that's where the real
problem comes in.
But then, no
portable user program can implement fgetc() at all, nor strlen() nor
sqrt() nor anything else in the Standard library: They all belong to
the implementation, so any attempt to implement them in portable C
is doomed from the word "Go."

The rules for reserved identifiers impose different restrictions on user
code than they do on standard library code. It is otherwise no problem
at all writing portable C code to implement things like strlen():

size_t strlen(const char *s)
{
size_t retval=0;
while(*s++)
retval++;
return retval;
}

Can you show me comparable code for an implementation of getc() that is
compatible with your fgetc() implementation above? Compatibility means
that, among other things, it can't call fgetc(). If it calls some other
standard library function to perform the read which fills the buffer,
then I'd like to see the implementation of that function too. Repeat
until you've shown the portable code which implements the actual read
itself. I'd really like to see what that looks like.
 
J

James Kuyper

What in it requires non-portable C?

Can you provide a portable version?

There's no C language construct that has, as it's standard-defined
semantics, the retrieval of a byte of data from an external device. Any
code you write that has that effect must necessarily be relying upon
something implementation-specific.

Are you thinking of implementing fgetc() by calling some other C
standard library functions? For example:

int fgetc(FILE *stream)
{
char c;
if(fread(&c, 1, 1, stream) != 1)
return EOF;
else
return c;
}

The problem with that approach is that fread() is defined as calling
fgetc(), which would cause infinite recursion. Because of the as-if
rule, fread() doesn't have to actually call fgetc(), but it does at
least have to produce the same effects as if it actually had called
fgetc(). All you've done is pass the issue on to fread(). Sooner or
later, somewhere along the way, there has to be a function that is part
of, or called by C standard library functions, which actually reads one
or more bytes of data from a data storage device without calling any
other functions (except possibly OS-specific functions). So how do you
do that in portable C (which cannot call OS-specific functions)?

The same is true of any other C standard library function that reads one
or more bytes of input from a stream - they all ultimately trace their
required behavior back to fgetc().
 
B

blmblm

0x80000000 is a positive value, equal to 2**31. It's not a valid
long value on any system where long is 32 bits (and LONG_MAX is at
most 2**31-1).

It commonly *converts* to a valid long value, -2**31 (ULONG_MIN),
but the result of the conversion is implementation-defined.

More of the pedantry that so endears this group to me. (No sarcasm
intended. :) ? )
 
B

blmblm

Keith Thompson said:
I think he meant the -999 that is used to stop the program...

I'm not sure who "he" is in this sentence (and for once I'm not just
making my usual quibble about the gender of the pronoun).

I'll agree that using some particular value to mean "no more input"
doesn't seem as satisfactory as just using end of file, though it's
not unusual in a beginning program and maybe not even very bad in
that context.

But my comment about disallowing one legitimate input was in
reference to signalling *errors* using something that could be
a legitimate return value -- that does seem less than optimal,
though it's not clear how one could do better without changing the
function signature.
 
N

Nick Keighley

"May or may not" indeed.  Sort of a :) here.  Some instructors
respond better than others to students "improving" (or actually
improving) their code.

I passed (with a good mark) a comp sci exam in which I started an
answer to a question with:- "the question you meant to ask was...".
The question as posed was nonsense (and it was the eam setter's second
attempt at framing it, I think a student who appealled against a bad
mark would have had a good case)
 
B

BartC

BartC said:
else
printf("\nThe %ldth integer read was %ld\n", i++, num);

I still find it grating that this prints "1th", "2th", and "3th"!

This does it better:

int i=1;
char* s;
....

else {
switch (i%100){
case 11: case 12: case 13: s="th"; break;
default:
switch (i%10){
case 1: s="st"; break;
case 2: s="nd"; break;
case 3: s="rd"; break;
default:s="th";
}
}
printf("\nThe %ld%s integer read was %ld\n", i++, s, num);
}

Or just change to:

printf("\nInteger #%d read was %ld\n", i++, num);
 
B

BartC

I'm not sure who "he" is in this sentence (and for once I'm not just
making my usual quibble about the gender of the pronoun).

It seems I interpreted your "And then" in the wrong way.

As for "he", that did mean you, but in the absence of clear evidence
otherwise, it's often taken to mean "he" or "she". Especially around here..
I'll agree that using some particular value to mean "no more input"
doesn't seem as satisfactory as just using end of file, though it's
not unusual in a beginning program and maybe not even very bad in
that context.

Yes, at least the user knows that -999 is not an input, but doesn't know
that -2147483648 isn't (and nor are most integers for that matter which
aren't in the narrow range of LONG_MIN(+1) to LONG_MAX.) But proper range
checking would be far too difficult for a beginner's exercise.
 
K

Keith Thompson

Joe Pfeiffer said:
Keith Thompson said:
Joe Pfeiffer said:
[...]
scanf() doesn't happen to be one of those functions; the required
behavior for scanf() can be implemented entirely in C code that calls
other C standard library functions, without using any of the other
members of the scanf() family. But if your argument were valid, it would
also apply to fgetc().

Actually, I was unaware that fgetc() had any non-C code in it -- what
does it do that requires assembler?

fgetc() cannot be written in *portable* C.

What in it requires non-portable C?

It could be implemented on top of some other input routine, but
eventually *something* has to perform some system-specific action to
perform the actual input (such as calling read(), for example).

Well, sure, but by that definition his assignment really is impossible,
since it calls for him to get input from stdin.

I think we can assume that he's allowed to call fgetc(), or fgets(),
or something similar.
 
K

Keith Thompson

Keith Thompson said:
I think we can assume that he's allowed to call fgetc(), or fgets(),
or something similar.

And in fact the assignment specifically allows (in fact, requires)
the use of getchar().
 
W

Willem

Keith Thompson wrote:
)> Well, sure, but by that definition his assignment really is impossible,
)> since it calls for him to get input from stdin.

I just reread the OP.
It calls for him to get input from 'the standard input stream'.

) I think we can assume that he's allowed to call fgetc(), or fgets(),
) or something similar.

No, he's not allowed to do that.
According to the assignment, he has to use getchar().


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
K

Keith Thompson

Willem said:
Keith Thompson wrote:
)> Well, sure, but by that definition his assignment really is impossible,
)> since it calls for him to get input from stdin.

I just reread the OP.
It calls for him to get input from 'the standard input stream'.

) I think we can assume that he's allowed to call fgetc(), or fgets(),
) or something similar.

No, he's not allowed to do that.
According to the assignment, he has to use getchar().

Which would be "something similar".
 
B

blmblm

It seems I interpreted your "And then" in the wrong way.

As for "he", that did mean you, but in the absence of clear evidence
otherwise, it's often taken to mean "he" or "she". Especially around here..

I don't notice it happening more here than in other newsgroups, but
yeah, it's not unusual usage. It still bugs me, but I just had that
debate in another newsgroup, and -- eh. "Get over it", maybe.
Yes, at least the user knows that -999 is not an input, but doesn't know
that -2147483648 isn't (and nor are most integers for that matter which
aren't in the narrow range of LONG_MIN(+1) to LONG_MAX.) But proper range
checking would be far too difficult for a beginner's exercise.

Now that you mention range checking .... That's *almost* a valid
argument for using 0x80000000 [*] to mean "invalid", since it's
not a value that's within the range specified by the standard for
"long". Then again, the fact that it isn't within that range means
it can't be returned from the function without at least impairing
portability ....

Which comes back to the real problem, which is how you signal errors
when all possible return values could be legit.
 

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,085
Messages
2,570,597
Members
47,219
Latest member
Geraldine7

Latest Threads

Top