我一直在寻找一种从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;
}
答案 0 :(得分:112)
您是否考虑过使用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
}
答案 1 :(得分:16)
这个例子有点冗长,但我相信它是检测终端尺寸的最便携方式。这也处理调整大小事件。
正如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);
}
答案 2 :(得分: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;
}
需要使用-ltermcap
进行编译。使用termcap可以获得许多其他有用的信息。有关详细信息,请使用info termcap
查看termcap手册。
答案 3 :(得分:2)
如果您已安装ncurses并正在使用它,则可以使用getmaxyx()
查找终端的尺寸。
答案 4 :(得分:1)
要添加更完整的答案,我发现对我有用的是使用@John_T的解决方案,并在Rosetta Code中添加了一些内容,并进行了一些故障排除以确定依赖性。可能效率不高,但是通过智能编程,您可以使其正常运行,而不必一直打开终端文件。
#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;
}
如果您确保不全部调用,但也许偶尔调用一次,则应该没问题,它甚至应该在用户调整终端窗口大小时更新(因为您正在打开文件并阅读每< / em>时间)。
如果您不使用TIOCGWINSZ
,请参见此表单https://www.linuxquestions.org/questions/programming-9/get-width-height-of-a-terminal-window-in-c-810739/上的第一个答案。
哦,别忘了free()
result
。
答案 5 :(得分:0)
假设您使用的是Linux,我认为您希望使用ncurses库 代替。我很确定你所拥有的ttysize东西不在stdlib中。
答案 6 :(得分:0)
所以这里不建议答案,但是:
linux-pc:~/scratch$ echo $LINES
49
linux-pc:~/scratch$ printenv | grep LINES
linux-pc:~/scratch$
好吧,我注意到,如果我调整GNOME终端的大小,那么LINES和COLUMNS变量将随之出现。
Kinda好像是GNOME终端自己在创建这些环境变量?
答案 7 :(得分:-1)
以下是已建议的环境变量事项的函数调用:
int lines = atoi(getenv("LINES"));
int columns = atoi(getenv("COLUMNS"));