Neu*_*onB -1 c pointers stdout
我正在尝试分析以下代码:
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);
当我运行此代码时,会观察到以下输出:
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:
我知道 fgetc 一次从 out(指向 stdout)获取一个字符的值并打印它直到到达文件末尾。
out=out-1 在这里做什么?如果 out 最初指向 stdout 文件的开头,那么它不应该也打印“Enter value:”中的字符。或者,如果它指向 stdout 文件的末尾,那么它不应该只从末尾打印一个字符吗?另外,为什么它首先需要用户输入?是因为getc吗?
抱歉问了很多问题。如果有人澄清这些疑问,这对我理解 C 将会非常有帮助。我在这里看到了相关问题,但没有找到任何特别解决我的疑问的问题。
这是未定义的行为。
\n在某些系统(即libc变体)上,三个标准流在数组中定义(例如):
FILE __stdlist[3];\n\n#define stdin  (&__stdlist[0])\n#define stdout (&__stdlist[1])\n#define stderr (&__stdlist[2])\n这就是为什么它似乎有效。因为:
\nFILE *out = stdout;\n\nout = out - 1;\n现在out是stdin。
但是,这只是其中之一 libc。它可以与其他系统完全不同。不要求[或保证]描述FILE符位于连续内存中。
如果你有(例如):
\nFILE *stderr;\nint x;\nFILE *stdout;\nint y;\nFILE *stdin;\nint z;\n那么,这个“诡计”就行不通了。
\n不要使用这个。
\n旁注:更改char ch;为int ch;. 否则,如果输入上有合法的 0xFF,它将被错误地解释为 -1(即EOF)。
更新:
\n\n\n在标准流在数组中定义的系统上,如第一个示例所示,OP代码的行为被完美定义,并且应该可靠地工作,因此不合格的“这是未定义的行为”是不正确的。但是,未指定是否定义了该行为,并且依赖该行为的程序并不严格遵守语言规范。\xe2\x80\x93\n约翰·博林格
\n
那么,如果我说unspecified,事情就可以了吗?如何可靠地检测到这一点?
\n即使在glibc[这是做#ifdef __GLIBC__什么的——我检查过],除非我们这样做或类似的事情,否则人们怎么知道。
否则,我认为我们必须假设stdout指向单个实例。如果我们这样做:
int val;\nint *ptr = &val;\nptr = ptr - 1;\n[无需查阅规范]我认为那是 UB。
\n我们可以很容易地得到:
\nFILE *__stdlist[3];\n\n#define stdin  (__stdlist[0])\n#define stdout (__stdlist[1])\n#define stderr (__stdlist[2])\n并且,数组元素是从(例如)malloc+一些设置初始化的。
而且,这又行不通。
\n更新#2:
\n\n\n如果我对您的答案的理解有误,请纠正我。因此,当我写出 out=out-1 时,它会进入 stdin 并等待用户输入。
\n
对于术语,我不确定我会说“进入”stdin。我会说它“指向”或“stdin设置为stdin”的值。
\n\n在我给出输入后,它从相同的标准输入读取并一一打印出字符。那是对的吗?\xe2\x80\x93\n神经元B
\n
那时,使用“技巧”[这是你不能使用的],我们out指向了与stdin指向的地址相同的地址。因此,最干净的方法是:
FILE *out = stdin;\n之后,这只是一个简单的循环:
\nout是] stdinEOF,则循环结束。stdout)。