C中的换行符不包含回车符?

3

有一个愚蠢的问题, 使用printf(),是否可能在stdout上换行而不使用换行符?如果不行,有什么提示可以覆盖2个或更多行吗?

我正在尝试生成多行进度条。 有什么想法吗?

编辑: 所以是的,我接受了下面的答案,尽管它对我的特定情况不起作用。 我正在尝试覆盖2个或更多行 而不是单行。

printf("12345\r");
fflush(stdout);
printf("67890\n");

其结果是:
$ ./a.out
67890

但我想要实现的是,用新数据覆盖2+行内容。类似于进度条,但有一个百分比数字。


2
为什么你不想使用换行符?你正在运行哪个操作系统? - devrobf
Linux,Ubuntu,但实际上这适用于任何版本。我不想使用换行符的原因是因为我认为如果我使用换行符,我将无法使用/r返回到“行”的开头。我有一个打印 "---->/r" 的代码,并且柱子会通过迭代增长。这有意义吗? - janjust
1
在C语言中,没有可移植的方法来实现这一点;你的问题是一个终端问题,而不是一个C语言问题,不幸的是,对于终端并没有这样的标准(据我所知)。你可以使用'\b'技巧,但要注意有些实现不能'\b'超过'\n'。 - autistic
@modifiablelvalue:OP已经清楚地说明了他想做什么。如果您认为OP不理解可移植性问题,那么您可以自由地解释它们,或者在我刚刚发布的答案中阅读它们。(有些论坛不鼓励讨论C标准未指定的构造;但这不是那些论坛之一。) - Keith Thompson
我在之前的评论中弄错了链接。我本意是要写“事实上,有终端标准”。 - Keith Thompson
显示剩余15条评论
2个回答

3

要重写一行(或部分)内容,您需要使用正确数量的退格字符。例如:

printf("some text");
printf("\b\b\b\bstuff");

将输出:

some stuff

对于简单的东西来说,这样做是可以的;但是对于更复杂的东西,您应该使用ncurses,它使用ANSI转义技巧来操作屏幕上的光标。


ncurses 假定你想占据整个屏幕;就我所知,它不适合像 OP 所希望的那样执行简单的任务而不删除已经打印出来的任何文本。 - Keith Thompson

2
如果您的终端(或者更可能是终端模拟器)支持VT100风格的转义序列,您可以打印特定的代码序列来控制光标位置、清除部分或全部屏幕/窗口等。
例如,要将光标向上移动1行:
printf("\x1b[A");
fflush(stdout);

要将光标向上移动两行,可以重复这个动作两次,或者:
printf("\x1b[2A"});
fflush(stdout);

这些通常被称为 ANSI转义码; 链接指向一个维基百科文章,列出了许多这样的代码。它们最初是由旧的DEC VT-100终端实现的,大多数现代终端和仿真器都模拟该终端。
还有这段文字:
printf("\x1b[J");
fflush(stdout);

将清除屏幕的一部分,从当前光标位置到底部。

这些序列应该足以满足您的需求。(它们可能在Windows命令窗口中无法工作。)

更加便携的方法是,如果您的系统支持,可以使用termcapterminfo来确定当前终端的正确命令序列(由$TERM环境变量确定)。tput命令可让您在命令行上执行此操作;有关更多信息,请参阅man tput。实际上,您现在很难找到不支持VT100兼容终端的支持termcap或terminfo的系统;打印原始转义序列严格来说并不是可移植的,但可能已经足够了。

建议:您的程序应该具有禁止任何此类控制序列的选项;例如,如果用户想要将输出重定向到文件,则不希望在文件中包含这些转义序列。一些程序仅在它们能够确定stdout是终端时才使用控制序列,但显式选项也是一个好主意。

*更新:*

这是我编写的一个程序,演示了如何使用terminfo来实现这一点。它应该适用于几乎任何类Unix系统。
#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <term.h>
#include <unistd.h>

int main(void) {
    const char *term = getenv("TERM");
    if (term == NULL) {
        fprintf(stderr, "TERM environment variable is not set\n");
        exit(EXIT_FAILURE);
    }
    setterm(term);
    for (int i = 0; i < 10; i ++) {
        putp(tparm(clr_eos));
        printf("%d\n%d\n", i, i+1);
        sleep(1);
        putp(tparm(parm_up_cursor, 2));
    }
    return 0;
}

啊,太好了,这肯定可以。我已经接受你的回答,因为它回答了我的问题。谢谢你的回答! - janjust

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