0

将大量数据非常快速地写入 C 子进程时,我遇到了 Broken Pipe 错误。

所以我正在从 python 脚本运行 ac 子进程:

process = subprocess.Popen("./gpiopwm", stdin=subprocess.PIPE)
while True:
    process.stdin.write("m2000\n")
    print "bytes written"

gpiopwm.c 的主循环部分:

printf("1\n");
while (1) {
    fgets(input,7,stdin);  // Takes input from python script
    printf("2\n");

    numbers = input+1;      // stores all but first char of input 
    char first = input[0];  // stores first char of input

    if (first=='m') {
        printf("3\n");
        printf("%s\n",numbers);
    }
}

但是,此操作的输出如下:

1
bytes written
Traceback (most recent call last):
     File "serial-receive-to-pwm.py", line 20, in <module>
     process.stdin.write("m2000\n")
IOError: [Errno 32] Broken pipe

C 程序显然在该fgets行中断,因为2从未打印过。我做错了什么?我怎样才能避免这种情况?

编辑:我已经更新了该fgets行,使其不包含取消引用参数,但仍然收到损坏的管道错误。

编辑: input初始化为char *input="m2000";

4

1 回答 1

2

如果你尝试从控制台运行你的 C 程序,你会看到它崩溃了。如果你在调试器中运行,你会看到它在这一行:

fgets(*input,7,stdin);

它似乎input是一个字符数组,当您取消引用它时,*input您传递的不是指针而是单个char值。这会导致未定义的行为和崩溃。

如果不是错误,那一行应该会给你一个来自编译器的非常大的警告消息。不要忽视警告信息,它们通常表明您做错了事并且可能是危险的。


一般提示:当开发一个应该从另一个程序调用的程序时,就像你在这里做的那样,首先测试程序以确保它可以工作。如果它不起作用,请先修复它。

最后一个提示:记住在目标字符串中包含换行符。您可能需要检查它并在它存在时将其删除。fgets


在最后一次编辑中,显示了input我们知道真正问题的声明:您正在尝试修改常量数据,并且您还想超出数据的范围进行写入。

当您input指向文字字符串时,您必须记住所有文字字符串都是只读的,您不能修改文字字符串。试图这样做是未定义的行为。更糟糕的是,您的字符串只有六个字符长,但您尝试向其写入七个字符。

首先更改 的声明和初始化input

char input[16] = "m2000\n";

这会将它声明为一个数组,位于堆栈上并且可以修改。然后做

while (fgets(input, sizeof(input), stdin) != NULL) { ... }

这完成了两件事:首先通过使用sizeof(input)大小,您可以确定fgets永远不会写出越界。其次,通过fgets在循环条件中使用调用,循环将在 Python 脚本被中断时结束,并且您不会永远循环无法读取任何内容,然后处理您从未读取过的数据。

于 2013-12-20T11:42:15.613 回答