Getting terminal width in C?

2018-12-31 17:56发布

I've been looking for a way to get the terminal width from within my C program. What I keep coming up with is something along the lines of:

#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);
}

But everytime I try that I get

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.)

Is this the best way to do this, or is there a better way? If not how can I get this to work?

EDIT: fixed code is

#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;
}

6条回答
闭嘴吧你
2楼-- · 2018-12-31 18:20
#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;
}

Needs to be compiled with -ltermcap . There is a lot of other useful information you can get using termcap. Check the termcap manual using info termcap for more details.

查看更多
深知你不懂我心
3楼-- · 2018-12-31 18:23

Have you considered using getenv() ? It allows you to get the system's environment variables which contain the terminals columns and lines.

Alternatively using your method, if you want to see what the kernel sees as the terminal size (better in case terminal is resized), you would need to use TIOCGWINSZ, as opposed to your TIOCGSIZE, like so:

struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);

and the full code:

#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
}
查看更多
唯独是你
4楼-- · 2018-12-31 18:34

Assuming you are on Linux, I think you want to use the ncurses library instead. I am pretty sure the ttysize stuff you have is not in stdlib.

查看更多
何处买醉
5楼-- · 2018-12-31 18:36

Here are the function calls for the already suggested environmental variable thing:

int lines = atoi(getenv("LINES"));
int columns = atoi(getenv("COLUMNS"));
查看更多
谁念西风独自凉
6楼-- · 2018-12-31 18:44

This example is a bit on the lengthy side, but I believe it's the most portable way of detecting the terminal dimensions. This also handles resize events.

As tim and rlbond suggests, I'm using ncurses. It guarantees a great improvement in terminal compatability as compared to reading environment variables directly.

#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);
}
查看更多
孤独总比滥情好
7楼-- · 2018-12-31 18:44

If you have ncurses installed and are using it, you can use getmaxyx() to find the dimensions of the terminal.

查看更多
登录 后发表回答