110

我一直在寻找一种从我的 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);
}

但每次我尝试得到

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

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

编辑:固定代码是

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

8 回答 8

146

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

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

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

和完整的代码:

#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
}
于 2009-06-21T01:40:34.640 回答
18

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);
}
于 2010-08-12T21:04:07.853 回答
13
#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.

于 2009-06-21T02:14:16.960 回答
3

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

于 2009-06-21T01:42:44.963 回答
3

To add a more complete answer, what I've found to work for me is to use @John_T's solution with some bits added in from Rosetta Code, along with some troubleshooting figuring out dependencies. It might be a bit inefficient, but with smart programming you can make it work and not be opening your terminal file all the time.

#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h> // ioctl, TIOCGWINSZ
#include <err.h>       // err
#include <fcntl.h>     // open
#include <unistd.h>    // close
#include <termios.h>   // don't remember, but it's needed

size_t* get_screen_size()
{
  size_t* result = malloc(sizeof(size_t) * 2);
  if(!result) err(1, "Memory Error");

  struct winsize ws;
  int fd;

  fd = open("/dev/tty", 0_RDWR);
  if(fd < 0 || ioctl(fd, TIOCGWINSZ, &ws) < 0) err(8, "/dev/tty");

  result[0] = ws.ws_row;
  result[1] = ws.ws_col;

  close(fd);

  return result;
}

If you make sure not to call it all but maybe every once in awhile you should be fine, it should even update when the user resizes the terminal window (because you're opening the file and reading it every time).

If you aren't using TIOCGWINSZ see the first answer on this form https://www.linuxquestions.org/questions/programming-9/get-width-height-of-a-terminal-window-in-c-810739/.

Oh, and don't forget to free() the result.

于 2020-01-31T05:58:25.733 回答
-1

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.

于 2009-06-21T01:40:53.190 回答
-1

So not suggesting an answer here, but:

linux-pc:~/scratch$ echo $LINES

49

linux-pc:~/scratch$ printenv | grep LINES

linux-pc:~/scratch$

Ok, and I notice that if I resize the GNOME terminal, the LINES and COLUMNS variables follow that.

Kinda seems like GNOME terminal is creating these environment variables itself?

于 2019-04-18T06:34:15.580 回答
-3

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

int lines = atoi(getenv("LINES"));
int columns = atoi(getenv("COLUMNS"));
于 2009-06-21T01:59:17.583 回答