将float转换为String并通过命名管道从C代码发送到Python

问题描述 投票:0回答:3

我想使用命名管道将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到string的转换我使用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?UeiEU11.417070

如果正确的结果应该是:

11.417070

注意:如果我尝试只发送“你好!”,它没有任何问题。

我在这里错过了什么?提前致谢。

python c linux named-pipes
3个回答
2
投票

第一个红旗是在sprintf电话中;它不知道你的目标缓冲区str有多大,所以如果你不小心可能会溢出。使用单个浮点数和64个字节,该步骤应该没问题。

但是,您没有存储返回值,因此此时您不知道格式化文本的大小。然后你使用了sizeof,它告诉你缓冲区有多大,而不是你刚放入多少数据。您可以使用基于字符串的函数(因为sprintf编写了一个以空字符结尾的字符串),例如strlen(测量字符串)或fputs(将字符串写入文件)。

更容易的捷径可能是首先使用fprintf,而不需要分配一个单独的缓冲区(它可能使用FILE中内置的缓冲区)来存储格式化的字符串。

使用write等函数在文件描述符(例如closeFILE使用)和fprintf(例如fdopen使用)之间进行转换是可能的,尽管不一定是可移植的或安全的。


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);

0
投票

我解决了这个问题,解决方案正在改变这条线

write(fd_fifo, str, sizeof(str));

write(fd_fifo, str, strlen(str));

© www.soinside.com 2019 - 2024. All rights reserved.