英文:
Reading from stdout using file pointer and decrementing it
问题
The code you provided is written in C and seems to be reading characters from the standard input (stdin) and printing them one by one until it reaches the end of the file (EOF). Let's address your questions:
-
out = out - 1;
is decrementing the file pointerout
by 1, which means it's moving one character position backward in the file. Sinceout
initially points tostdout
, this operation is shifting the file pointer backward in the standard output stream. It doesn't affect the standard input stream (where user input is expected). -
The code expects user input because of
ch = fgetc(out);
. It reads characters from the file stream pointed to byout
, which, after the decrement operation, is still connected tostdout
. So, it doesn't read from the standard input; instead, it reads from the standard output, which may not be what was intended.
In summary, the code is a bit unconventional and may not behave as expected. If the goal is to read user input, you should use ch = fgetc(stdin);
to read from the standard input stream, and you don't need the out = out - 1;
line.
If you have further questions or need clarification, please feel free to ask.
英文:
I am trying to analyze the following piece of code:
FILE* out=stdout;
printf("\nEnter value: \n");
out=out-1;
char ch;
while(ch!=EOF){
ch=fgetc(out);
printf("\nValue printed: %c\n",ch);
}
fclose(out);
The following output is observed when I run this code:
Enter value:
IWantToC
Value printed: I
Value printed: W
Value printed: a
Value printed: n
Value printed: t
Value printed: T
Value printed: o
Value printed: C
Value printed:
I understand that fgetc is fetching the value from out(which is pointing to stdout) one character at a time and printing it till it reaches the file end.
What is out=out-1 doing here? If out was originally pointing to the beginning of the stdout file, then shouldn't it be printing chars from "Enter value:" as well. Or if it is pointing to the end of the stdout file, then shouldn't it be printing only one character from the end? Also, why is it expecting user input in the first place? Is it because of getc?
Sorry for the many questions. If someone clarifies those doubts, it will be very helpful for me to understand C. I have seen related questions here but haven't found any particularly addressing my queries.
答案1
得分: 5
这是未定义行为。
在某些系统上(即libc
变体),三个标准流以数组形式定义(例如):
FILE __stdlist[3];
#define stdin (&__stdlist[0])
#define stdout (&__stdlist[1])
#define stderr (&__stdlist[2])
这就是为什么它“似乎”能工作的原因。因为使用:
FILE *out = stdout;
out = out - 1;
现在,out
是 stdin
。
但这只是一个libc
。与其他系统完全不同是完全可能的。没有要求[或保证] FILE
描述符在连续的内存中。
如果你有(例如):
FILE *stderr;
int x;
FILE *stdout;
int y;
FILE *stdin;
int z;
那么“技巧”就不会起作用。
不要使用这个。
旁注: 将 char ch;
改为 int ch;
。否则,如果输入得到一个合法的 0xFF,它将被错误地解释为 -1(即 EOF
)。
更新:
在标准流在数组中定义的系统上,就像你的第一个例子中显示的那样,OP 代码的行为是完全定义的,并且应该可以可靠地工作,因此对“它是未定义行为”的不加限定的说法是不正确的。然而,行为是否被定义是未指定的,并且依赖于该行为的程序不符合语言规范。 –
约翰·博林格
那么,如果我说“未指定”,事情就会好吗?有什么方法可以可靠地检测这一点呢?
即使在 glibc
上[我检查过的地方],除非我们进行 #ifdef __GLIBC__
或类似操作,否则我们怎么知道呢。
否则,我认为我们必须假设 stdout
指向一个_单一_实例。如果我们这样做:
int val;
int *ptr = &val;
ptr = ptr - 1;
[不查阅规范] 我认为这是未定义行为。
我们也可能有:
FILE *__stdlist[3];
#define stdin (__stdlist[0])
#define stdout (__stdlist[1])
#define stderr (__stdlist[2])
而且,数组元素是从(例如)malloc
+ 一些设置中初始化的。
同样,它不会起作用。
更新 #2:
请纠正我是否错误地理解了您的回答。所以,当我写
out = out - 1
时,它进入stdin
并等待用户输入。
对于术语,我不确定我会说“进入 stdin
”。我会说它“指向 stdin
”或“被设置为 stdin
的值”。
在我提供输入后,它从相同的 stdin 输入读取并逐个字符打印出来。这是正确的吗? –
神经元B
在那一点上,使用“技巧” [你不能使用],我们有 out
指向与 stdin
指向相同的地址。因此,用一个_干净_的方式做到这一点是:
FILE *out = stdin;
之后,这只是一个简单的_循环_:
- 从
out
流中读取一个字符[现在是stdin
] - 如果读取的字符是
EOF
,循环结束。 - 将其打印到显示器上(即
stdout
)。
英文:
It's undefined behavior.
On some systems (i.e. libc
variant), the three standard streams are defined in an array (e.g):
FILE __stdlist[3];
#define stdin (&__stdlist[0])
#define stdout (&__stdlist[1])
#define stderr (&__stdlist[2])
That's why it seems to work. Because with:
FILE *out = stdout;
out = out - 1;
Now, out
is stdin
.
But, this is just one libc
. It can totally different with other systems. There is no requirement [or guarantee] that the FILE
descriptors are in contiguous memory.
If you had (e.g.):
FILE *stderr;
int x;
FILE *stdout;
int y;
FILE *stdin;
int z;
Then, the "trick" would not work.
Do not use this.
Side note: Change char ch;
into int ch;
. Otherwise, if you got a legitimate 0xFF on the input, it would erroneously be interpreted as -1 (i.e. EOF
).
UPDATE:
>On a system where the standard streams are defined in an array, as shown in your first example, the behavior of the OP's code is perfectly well defined, and should be expected to work reliably, so an unqualified "It's undefined behavior" is incorrect. However, it is unspecified whether the behavior is defined, and a program that relies on that behavior does not conform strictly to the language spec. –
John Bollinger
So, if I said unspecified, things would be okay? How would one reliably detect this?
Even on glibc
[which does this--I checked], how does one know unless we do #ifdef __GLIBC__
or some such.
Otherwise, I think we must assume stdout
points to a single instance. If we do:
int val;
int *ptr = &val;
ptr = ptr - 1;
[Without consulting the spec] I think that's UB.
We could just as easily have:
FILE *__stdlist[3];
#define stdin (__stdlist[0])
#define stdout (__stdlist[1])
#define stderr (__stdlist[2])
And, the array elements are initialized from (e.g.) malloc
+ some setup.
And, again it won't work.
UPDATE #2:
>please correct me if I am wrong in understanding your answer. So, when I write out=out-1, it goes into stdin and waits for user input.
For terminology, I'm not sure I would say "goes into stdin
". I'd say it "points to stdin
" or "is set to the value of stdin
".
>After I give the input, it reads from the same stdin input and prints out the characters one by one. Is that correct? –
NeuronB
At that point, using the "trick" [which, you can't use], we have out
pointing to the same address as stdin
points to. So, the clean way to do this is:
FILE *out = stdin;
After that, this is just a simple loop that:
- reads one char from the
out
stream [which is nowstdin
] - if the char read is
EOF
, the loop is ended. - prints it to the display (i.e.
stdout
).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论