这里可能有很多关于相同的问题,但到目前为止我都没有。
我有一个C程序如下:
#include <stdio.h>
#include <sys/stat.h>
long size(FILE *st_in) {
struct stat st;
if (fstat(fileno(st_in), &st) == 0)
return st.st_size;
return -1;
}
int main (){
FILE *file = stdin;
long s1, s2;
s1 = size(file);
printf("Size is %ld\n", s1);
fprintf(stderr, "%d", 1);
return 0;
}
我将其编译为输出a.out。
我有一个xml文件'sample.xml'
<sample>
<tag>Hello</tag>
<tag>Cool</tag>
</sample>
然后我有这个perl代码
#!/usr/bin/perl
use warnings;
use IPC::Open2;
open FILE, "sample.xml" or die $!;
my @xmlfile = <FILE>;
my $pid = open2(*Reader, *Writer, "./a.out");
print Writer "@xmlfile";
waitpid($pid, 0);
my @got = <Reader>;
close Writer;
close Reader;
close $pid;
print "Output got is\n";
print @got;
如果我运行通过stdin传递simple.xml的C程序,我得到以下内容:
[bharath@xml 18:22:34]$ ./a.out < sample.xml
Size is 60
当我运行perl代码时,我希望大小为60.但我得到0。
[bharath@xml 18:22:42]$ ./firmware.pl
Output got is
Size is 0
那么我该如何解决这个问题呢?我需要从perl中的@array传递sample.xml。并且C程序中的stderr整数应该存储在一个单独的变量中,而来自C程序的stdout应该存储在perl中的另一个单独变量中。我认为这可能需要使用open3但我不知道如何使用。任何工作实例都将受到高度赞赏。
答案 0 :(得分:4)
更新:至于您的评论,Ilmari Karonen已经向您解释过,管道没有文件大小,因为它是一个数据流,程序不知道这个流有多大。
你有两个问题:你的C程序不能正常工作,你的Perl程序也没有工作,因为它陷入了僵局。你不能一起测试这两件事。将这两个问题分开。例如,首先使用shell中的管道尝试您的程序。
cat sample.xml | ./a.out
Size is 60
最初它没有用。为了使它工作,我使用了这个修改过的C程序:可以通过计算所有收到的字符直到EOF来计算流的大小。
#include <stdio.h>
int main (){
long size = 0;
int ch;
FILE *file = stdin;
if (!file) {
return 2;
}
while ((ch = getc(file)) != EOF) {
++size;
}
printf("Size is %ld\n", size);
fprintf(stderr, "%d", 1);
return 0;
}
至于你的Perl程序,你有一个死锁因为两个程序都处于等待状态,为了解决这个问题,我稍微改变了指令的顺序:
#!/usr/bin/perl -w
use strict;
use IPC::Open2;
open FILE, "sample.xml" or die $!;
my @xmlfile = <FILE>;
my $pid = open2(*Reader, *Writer, './a.out 2> /dev/null');
print Writer @xmlfile;
close(Writer);
my @got = <Reader>;
close(Reader);
waitpid($pid, 0);
print "Output got is: ";
print @got;
在我开始阅读之前,你可以看到我关闭了编写器,因为我的C程序旨在获取所有输入,然后进行输出。现在,整个进程间通信将起作用:
./program.pl
Output got is: Size is 60
作为附注,您不需要关闭$ pid,因为它只是表示子进程ID的数字。在其他情况下,您可能想要探索non blocking reads,但会使逻辑变得更复杂。
原始答案:没有解决海报问题,因为他想使用IPC。
您可以将文件名作为sample.xml添加到$ cmd吗?你可以使用反引号运算符来捕获输出,chomp删除换行符,输出将是$ out。
#!/usr/bin/perl
$cmd = './a.out < sample.xml 2> /dev/null';
$out = `$cmd`;
chomp $out;
print "out='$out'\n";
我想你的例子是找到一种在C和Perl之间进行通信的方法,因为当然,如果只是文件大小,它在Perl中会更容易:
#!/usr/bin/perl
print -s 'sample.xml';
print "\n";
答案 1 :(得分:2)
我很确定问题不在您的Perl代码中,而是在C程序中。尝试运行
cat sample.xml | ./a.out
在shell中,你应该得到与你的Perl程序相同的输出。问题是,在这两种情况下,stdin
将是管道而不是文件,fstat()
显然不能为管道返回任何有意义的大小。
无论如何,在fstat()
上调用stdin
对我来说似乎是不好的做法 - 你不应该依赖于本质上由shell做出的优化。关于stdin
的唯一真正保证是你可以(尝试)从中读取数据;除此之外,它可能是任何东西:文件,管道,tty等。