使用fseek和stdout

7

当文件指针 arg 是 stdout 时,是否可以使用 fseek?

我尝试过在一个场景中使用它,当我试图用 ")" 覆盖逗号分隔列表中的最后一个 "," 时。

例如:

fprintf(stdout, "1,2,3,4,");

fseek(stdout, -1, SEEK_CUR);

fprintf(stdout, ")");

要实现:

1、2、3、4)

而非

1、2、3、4,)

不幸的是,我输出了后者。


1
printf(...) 相当于并且更清晰地表达了 fprintf(stdout, ...) - Keith Thompson
1
无论什么能起作用或不起作用,我认为不产生尾随逗号要干净得多,而不是摆弄输出流。 - Nisse Engström
我自己也得出了同样的结论 - 调整文件指针位置显然是一个麻烦的问题。 - bph
我已经更新了我的答案,提供了一个解决打印逗号分隔列表问题的替代方案。 - Keith Thompson
2个回答

8

如果stdout引用的是可寻址流,则可以成功使用fseek,否则无法使用。

如果程序的标准输出将会被发送到终端或类似设备(通常是默认设置)或管道,则fseek将失败。如果它将要被发送到文件中,因为您执行了带有重定向输出的程序,则fseek可以像对任何其他文件一样工作。

每次调用fseek时,您应该检查其返回值以查看它是否成功或失败。

假定stdout是可寻址的可能是不好的做法,因为这是一个非常普遍的错误假设。

您的目标是打印一系列具有", "分隔符的项目,但在第一个项目之前和最后一个项目之后不需要分隔符。既不使用fseek也不使用打印'\b'是实现此目标的好方法。而是仅在未刚刚打印完列表中的最后一个项目时才打印逗号。检测这一点可能有些棘手。

但更简单的方法是在每个项目之前加上逗号,除非它是第一个项目。您不能总是知道您正在打印序列的最后一个值。您可以始终知道您是否正在打印第一个值。

伪代码:

bool is_first_item = true
for each item
    if is_first_item
        is_first_item = false
    else
        print ", "
    end if
    print item
end for 

1
stdout被重定向到管道时,寻找并不一定会失败。据推测,这在我的简短测试中是有效的,因为输出仍然停留在缓冲区中。 - Nisse Engström

4

fseek无法在stdout上使用。相反,您可以使用退格字符'\b'将光标向后移动一个空格:

fprintf(stdout, "1,2,3,4,");

fprintf(stdout, "\b)");

注意:只有当stdout指向终端并且没有被重定向到文件或管道时,这将仅仅起作用。此外,如果光标当前位于行的开头,则不能保证其有效。一般来说,只有少数情况下才能使用此功能。

3
假设stdout指向终端或者打印\b字符会移动光标是没有根据的。如果程序输出被重定向到一个文件,那么你只是把"1,2,3,4,\b"写入那个文件而已。请注意不要改变原意。 - Keith Thompson
1
@KeithThompson 我添加了一个澄清。 - Drew McGowen
1
有其他情况被忽略了。如果stdout要发送到管道呢? - Keith Thompson
1
@KeithThompson 我可以说我有点随意地使用了“文件”这个术语 :P 但无论如何,我已经修复了它。 - Drew McGowen
1
我已经撤回了我的反对票,但是打印 '\b' 是否可以合理替代 fseek 调用并不明确(即使问题中的 fseek 能够工作,这种方法是否合理也不确定)。 - Keith Thompson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接