#c #cpp #linux
Случайно наткнулся на загадочное (для меня) поведение программы. Вот протокол avp@avp-ubu1:~/src/ig/tst$ cat tpoll.c #include#include #include main () { int lw = write(fileno(stdin),"xaxa\n",5); char buf[100]; int lr = read(fileno(stdout),buf,99); buf[(lr > 0)? lr:0] = 0; printf ("lw = %d lr = %d buf = [%s]\n",lw,lr,buf); exit(0); } avp@avp-ubu1:~/src/ig/tst$ gcc tpoll.c avp@avp-ubu1:~/src/ig/tst$ ./a.out xaxa js39993 lw = 5 lr = 8 buf = [js39993 ] avp@avp-ubu1:~/src/ig/tst$ g++ tpoll.c avp@avp-ubu1:~/src/ig/tst$ ./a.out xaxa jsk393 lw = 5 lr = 7 buf = [jsk393 ] avp@avp-ubu1:~/src/ig/tst$ avp@avp-ubu1:~/src/ig/tst$ cat /etc/issue Ubuntu 10.04.4 LTS \n \l avp@avp-ubu1:~/src/ig/tst$ env | grep TERM TERM=xterm COLORTERM=gnome-terminal avp@avp-ubu1:~/src/ig/tst$ ps -ef | grep term avp 1536 1 0 Oct24 ? 00:00:03 gnome-terminal avp 2223 1538 0 01:17 pts/0 00:00:00 grep --color=auto term avp@avp-ubu1:~/src/ig/tst$ avp@avp-ubu1:~/src/ig/tst$ Скажу откровенно, сам пока еще ответ нигде не искал. Возможно это общеизвестный факт, а может нет. Если кто знает, почему такое происходит, объясните, пожалуйста. В винде все, как и ожидается c:/Users/avp/src/cc/hashcode $ gcc tpoll.c c:/Users/avp/src/cc/hashcode $ ./a lw = -1 lr = -1 buf = [] c:/Users/avp/src/cc/hashcode $ Реально убунта стоит под виндой в VirtualBox. UPD Дополнил программу и немного позапускал. Видимо обычно sh запускается с дапами одного девайса и это наследуется. В виде исключения нашел mpi на кластере. #include #include #include #include #include static void pristat (char *what, struct stat *sbuf) { printf ("%s stat:\n S_ISREG %s, S_ISCHR %s, S_ISFIFO %s, S_ISSOCK %s\n\ st_dev=%ld st_ino=%ld st_rdev=%ld st_mode=%lx\n", what, S_ISREG(sbuf->st_mode)? "Yes":"No", S_ISCHR(sbuf->st_mode)? "Yes":"No", S_ISFIFO(sbuf->st_mode)? "Yes":"No", S_ISSOCK(sbuf->st_mode)? "Yes":"No", (long)sbuf->st_dev, (long)sbuf->st_ino, (long)sbuf->st_rdev, (long)sbuf->st_mode); } static char* stdiff (struct stat *sbuf1, struct stat *sbuf2, char *buf) { *buf = 0; if (sbuf1->st_dev != sbuf2->st_dev) strcat(buf,"st_dev "); if (sbuf1->st_ino != sbuf2->st_ino) strcat(buf,"st_ino "); if (sbuf1->st_mode != sbuf2->st_mode) strcat(buf,"st_mode "); if (sbuf1->st_nlink != sbuf2->st_nlink) strcat(buf,"st_nlink "); if (sbuf1->st_uid != sbuf2->st_uid) strcat(buf,"st_uid "); if (sbuf1->st_gid != sbuf2->st_gid) strcat(buf,"st_gid "); if (sbuf1->st_rdev != sbuf2->st_rdev) strcat(buf,"st_rdev "); if (sbuf1->st_size != sbuf2->st_size) strcat(buf,"st_size "); if (sbuf1->st_blksize != sbuf2->st_blksize) strcat(buf,"st_blksize "); if (sbuf1->st_blocks != sbuf2->st_blocks) strcat(buf,"st_blocks "); if (sbuf1->st_atime != sbuf2->st_atime) strcat(buf,"st_atime "); if (sbuf1->st_mtime != sbuf2->st_mtime) strcat(buf,"st_mtime "); if (sbuf1->st_ctime != sbuf2->st_ctime) strcat(buf,"st_ctime "); return buf; } main () { int lw = write(fileno(stdin),"xaxa\n",5); char buf[1000]; int lr = read(fileno(stdout),buf,99); buf[(lr > 0)? lr:0] = 0; printf ("lw = %d lr = %d buf = [%s]\n",lw,lr,buf); fprintf(stderr,"Try read stderr:"); lr = read(fileno(stderr),buf,99); buf[(lr > 0)? lr:0] = 0; printf ("stderr: lr = %d buf = [%s]\n",lr,buf); struct stat sbufi, sbufo, sbufe; fstat(fileno(stdin),&sbufi); fstat(fileno(stdout),&sbufo); fstat(fileno(stderr),&sbufe); int diffio = memcmp(&sbufi,&sbufo,sizeof(sbufi)), diffoe = memcmp(&sbufi,&sbufo,sizeof(sbufi)); if (diffio == 0 && diffoe == 0) pristat("All",&sbufi); else { printf ("stdin & stdout differ in %s\nstdout & stderr differ in %s\n", stdiff(&sbufi,&sbufo,buf), stdiff(&sbufo,&sbufe,&buf[500])); pristat("stdin",&sbufi); pristat("stdout",&sbufo); pristat("stderr",&sbufe); } exit(0); } Это обычная Xubuntu (в Emacs eshell то же самое) avp@avp-xub11:~/src/tst$ gcc tstdio.c avp@avp-xub11:~/src/tst$ ./a.out xaxa read STDOUT lw = 5 lr = 12 buf = [read STDOUT ] Try read stderr:read STDERR stderr: lr = 12 buf = [read STDERR ] All stat: S_ISREG No, S_ISCHR Yes, S_ISFIFO No, S_ISSOCK No st_dev=11 st_ino=6 st_rdev=34819 st_mode=2190 avp@avp-xub11:~/src/tst$ avp@avp-xub11:~/src/tst$ Это RedHat на кластере, сначала вычислительный узел по mpi, потом "рабочая среда". [root@manager soft]# mpirun -hosts cn01 ./a.out lw = -1 lr = -1 buf = [] stderr: lr = -1 buf = [] stdin & stdout differ in st_ino stdout & stderr differ in st_ino stdin stat: S_ISREG No, S_ISCHR No, S_ISFIFO Yes, S_ISSOCK No st_dev=8 st_ino=333128 st_rdev=0 st_mode=1180 stdout stat: S_ISREG No, S_ISCHR No, S_ISFIFO Yes, S_ISSOCK No st_dev=8 st_ino=333129 st_rdev=0 st_mode=1180 stderr stat: S_ISREG No, S_ISCHR No, S_ISFIFO Yes, S_ISSOCK No st_dev=8 st_ino=333130 st_rdev=0 st_mode=1180 Try read stderr:[root@manager soft]# [root@manager soft]# [root@manager soft]# ./a.out xaxa jkks lw = 5 lr = 5 buf = [jkks ] Try read stderr:Cluster manager stderr: lr = 16 buf = [Cluster manager ] All stat: S_ISREG No, S_ISCHR Yes, S_ISFIFO No, S_ISSOCK No st_dev=11 st_ino=3 st_rdev=34816 st_mode=2190 [root@manager soft]# Можно подвести итог. Когда увидишь такое в первый раз, то крайне неожиданно (а я наткнулся в результате своей невнимательности в тестовой программе), а потом понимаешь, что а почему бы и нет?
Ответы
Ответ 1
Хе, забавно. Наверное, все эти стандартные файловые дескрипторы присоединены к /dev/tty, который во всех случаях открывался с O_RDWR.Ответ 2
Не сразу дошло, что не так. Да, в линуксе можно писать в stdin, я даже как-то обнаружил у себя такой код. Читать из stdout не догадался. Дело в реализации, в винде так нельзя.
Комментариев нет:
Отправить комментарий