我想使用命名管道将浮点值从C代码发送到Python代码。我正在将接收到的值打印到Python端的终端中,但是与值本身一起,还会显示乱码。
管道打开:
void Init_FIFO(void)
{
// FIFO file path
char * bldc_fifo = "/tmp/bldc_fifo";
// Creating the named FIFO -- mkfifo(<pathname>, <permission>)
mkfifo(bldc_fifo, 0666);
// Open FIFO to write/read data
fd_fifo = open(bldc_fifo, O_RDWR | O_NONBLOCK);
//fd_fifo = open(bldc_fifo, O_WRONLY | O_RDONLY | O_NONBLOCK);
}
为了将float转换为字符串,我使用sprintf,下面给出了代码,
void SendDataOverFifo(float angle)
{
char str[64];
unsigned char writeBuffer[] = "Hello!";
Init_FIFO();
sprintf(str, "%f\n", angle);
write(fd_fifo, str, sizeof(str));
//write(fd_fifo, writeBuffer, sizeof(writeBuffer));
close(fd_fifo);
}
然后在Python端接收代码,我使用此
#!/usr/bin/python
import os
import errno
import time
FIFO = '/tmp/bldc_fifo'
try:
os.mkfifo(FIFO)
except OSError as oe:
if oe.errno != errno.EEXIST:
raise
print("Opening FIFO...")
with open(FIFO, encoding='utf-8', errors='ignore') as fifo:
print("FIFO opened")
while True:
time.sleep(0.1)
data = fifo.read()
print(data)
我得到的输出是这样的
i-W?UOeiEU11.417070
正确的结果应为:
11.417070
注意事项:如果我尝试仅发送“ Hello!”,那么它将正常工作。
我在这里想念什么?预先感谢。
答案 0 :(得分:2)
第一个红色标志在sprintf
调用中;它不知道目标缓冲区str
有多大,因此如果不注意可能会溢出。使用单个浮点数和64个字节,该步骤应该没问题。
但是,您没有存储返回值,因此,此时您还不知道格式化文本的大小。然后,您使用了sizeof
,它告诉您缓冲区有多大,而不是您刚刚放入了多少数据。您可以使用基于字符串的函数(因为sprintf
写了一个以nul结尾的字符串),例如strlen
(用于测量字符串)或fputs
(用于将字符串写入文件) 。
一个更容易的快捷方式可能是首先使用fprintf
,而无需分配单独的缓冲区(它可能使用FILE
中内置的缓冲区)来存储格式化的字符串。
可以在文件描述符(例如write
和close
使用)和FILE
(例如fprintf
使用之间进行转换,尽管不一定是便携式或安全的)使用fdopen
之类的功能。
答案 1 :(得分:1)
该行:
write(fd_fifo, str, sizeof(str));
导致将非初始化内存写入fifo。您不想编写整个str
缓冲区,而只写要传递的字符串的大小。您可以使用snprintf
通过strlen(str)
的返回值找出来。
int ret = sprintf(str, "%f", ...);
assert(ret > 0); // just to be safe
write(fd_fifo, str, ret);
由于您的原因,使用sprintf
是不安全的。使用snprintf
来防止堆栈溢出。
int ret = snprintf(str, sizeof(str), ....
// no changes
这样,sprintf
永远不会在缓冲区中写入超过sizeof(str)
个字符。
但是,最好的方法是没有静态分配的缓冲区。您可以使用fdopen
:
FILE *f = fdopen(fd_fifo, "w");
if (f == NULL) {
// handle error
}
int ret = fprintf(f, "%f", ...);
if (ret < 0) {
// handle error
}
fclose(f);
或事先了解缓冲区的大小,再调用malloc,然后再次使用snprintf:
int ret = sprintf(NULL, "%f", ...);
assert(ret > 0);
char *str = malloc(ret * sizeof(char));
if (str == NULL) {
// handler error
}
ret = snprintf(str, "%f", ...);
write(fd_fifo, str, ret);
free(str);
答案 2 :(得分:0)
我解决了问题,解决方案是更改此行
write(fd_fifo, str, sizeof(str));
到
write(fd_fifo, str, strlen(str));