在C中获得终端宽度?

aus*_*tin 84 c linux terminal width

我一直在寻找一种从我的C程序中获取终端宽度的方法.我一直想出的是:

#include <sys/ioctl.h>
#include <stdio.h>

int main (void)
{
    struct ttysize ts;
    ioctl(0, TIOCGSIZE, &ts);

    printf ("lines %d\n", ts.ts_lines);
    printf ("columns %d\n", ts.ts_cols);
}
Run Code Online (Sandbox Code Playgroud)

但每次我尝试我得到

austin@:~$ gcc test.c -o test
test.c: In function ‘main’:
test.c:6: error: storage size of ‘ts’ isn’t known
test.c:7: error: ‘TIOCGSIZE’ undeclared (first use in this function)
test.c:7: error: (Each undeclared identifier is reported only once
test.c:7: error: for each function it appears in.)
Run Code Online (Sandbox Code Playgroud)

这是最好的方法吗,还是有更好的方法?如果不是,我怎么能让它工作?

编辑:固定代码是

#include <sys/ioctl.h>
#include <stdio.h>

int main (void)
{
    struct winsize w;
    ioctl(0, TIOCGWINSZ, &w);

    printf ("lines %d\n", w.ws_row);
    printf ("columns %d\n", w.ws_col);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Joh*_*n T 117

你考虑过使用getenv()吗?它允许您获取包含终端列和行的系统环境变量.

或者使用您的方法,如果您想查看内核看到的终端大小(在终端调整大小的情况下更好),您需要使用TIOCGWINSZ,而不是TIOCGSIZE,如下所示:

struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
Run Code Online (Sandbox Code Playgroud)

和完整的代码:

#include <sys/ioctl.h>
#include <stdio.h>
#include <unistd.h>

int main (int argc, char **argv)
{
    struct winsize w;
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);

    printf ("lines %d\n", w.ws_row);
    printf ("columns %d\n", w.ws_col);
    return 0;  // make sure your main returns int
}
Run Code Online (Sandbox Code Playgroud)

  • 对于`STDOUT_FILENO`,你需要`#include <unistd.h>`. (8认同)
  • 是的但宽度不是一个环境变量,它与术语的静态不同. (4认同)
  • 如果有人在程序执行期间调整终端大小,它不会为您提供_current_终端大小. (4认同)
  • 虽然我们可以在环境中看到`LINES`和`COLUMNS`变量,但它们似乎没有被导出。所以无法从您的 C 程序访问。 (2认同)

gam*_*men 17

这个例子有点冗长,但我相信它是检测终端尺寸最便携的方式.这也处理调整大小事件.

正如tim和rlbond所说,我正在使用ncurses.与直接读取环境变量相比,它保证了终端兼容性的极大改进.

#include <ncurses.h>
#include <string.h>
#include <signal.h>

// SIGWINCH is called when the window is resized.
void handle_winch(int sig){
  signal(SIGWINCH, SIG_IGN);

  // Reinitialize the window to update data structures.
  endwin();
  initscr();
  refresh();
  clear();

  char tmp[128];
  sprintf(tmp, "%dx%d", COLS, LINES);

  // Approximate the center
  int x = COLS / 2 - strlen(tmp) / 2;
  int y = LINES / 2 - 1;

  mvaddstr(y, x, tmp);
  refresh();

  signal(SIGWINCH, handle_winch);
}

int main(int argc, char *argv[]){
  initscr();
  // COLS/LINES are now set

  signal(SIGWINCH, handle_winch);

  while(getch() != 27){
    /* Nada */
  }

  endwin();

  return(0);
}
Run Code Online (Sandbox Code Playgroud)

  • 但是从信号处理程序调用initscr和endwin是否真的安全?它们至少没有列在`man 7 signal`中的异步信号安全API中 (3认同)
  • @AlexisWilke:包括“OK”和“ERR”。他们多么“善良”,帮助我们填补了生活中的空白:-( (2认同)

Jul*_*ano 12

#include <stdio.h>
#include <stdlib.h>
#include <termcap.h>
#include <error.h>

static char termbuf[2048];

int main(void)
{
    char *termtype = getenv("TERM");

    if (tgetent(termbuf, termtype) < 0) {
        error(EXIT_FAILURE, 0, "Could not access the termcap data base.\n");
    }

    int lines = tgetnum("li");
    int columns = tgetnum("co");
    printf("lines = %d; columns = %d.\n", lines, columns);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

需要编译-ltermcap.使用termcap可以获得许多其他有用的信息.info termcap有关详细信息,请查看termcap手册.

  • 我知道这个评论是在事实发生6年之后,但请解释你2048年的神奇数字... (2认同)
  • 实际上,这个答案做出了太多假设而不正确。 (2认同)
  • 对于任何好奇的人,2048 缓冲区大小在 GNU termcap 文档中进行了解释:https://www.gnu.org/software/termutils/manual/termcap-1.3/html_mono/termcap.html#SEC4 还有很多其他阅读这篇文章的人可能会发现其中的内容很有用。 (2认同)