Reputation: 141
I would like to send float values from C code into Python code using named pipes. I am printing the received values into terminal in the Python side, however along with the value itself, gibberish characters are also displayed.
Pipe opening:
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);
}
For the conversion of float to string I use sprintf and the code is given below,
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);
}
Then for receiving the code in the Python side, I use this
#!/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)
The output I am getting is something like this
i-W ?UOeiEU11.417070
Where the correct result should be:
11.417070
A note: If I try to send only "Hello!", it works without any problems.
What am I missing here? Thanks in advance.
Upvotes: 0
Views: 582
Reputation: 141
I solved the problem, the solution was changing this line
write(fd_fifo, str, sizeof(str));
to
write(fd_fifo, str, strlen(str));
Upvotes: 0
Reputation: 140880
The line:
write(fd_fifo, str, sizeof(str));
is causing unintialized memory to be written to the fifo. You don't want to write the whole str
buffer, only the size of the string you want to pass. And you can find that out by snprintf
return value of by using strlen(str)
.
int ret = sprintf(str, "%f", ...);
assert(ret > 0); // just to be safe
write(fd_fifo, str, ret);
Using sprintf
is unsafe for you cause. Use snprintf
to protect against stack overflow.
int ret = snprintf(str, sizeof(str), ....
// no changes
That way sprintf
will never write more than sizeof(str)
characters into the buffer.
However the best way is to not have a statically allocated buffer. You can use fdopen
:
FILE *f = fdopen(fd_fifo, "w");
if (f == NULL) {
// handle error
}
int ret = fprintf(f, "%f", ...);
if (ret < 0) {
// handle error
}
fclose(f);
or get to know the size of buffer beforehand, call malloc, and snprintf again:
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);
Upvotes: 1
Reputation: 15877
The first red flag is in the sprintf
call; it doesn't know how large your target buffer str
is, so could overflow if you're not careful. With a single float and 64 bytes, that step should be fine.
However, you didn't store the return value, so at this point you don't know how large the formatted text is. Then you used sizeof
, which tells you how large the buffer is, not how much data you just put into it. You could use a string-based function (since sprintf
wrote a nul-terminated string), such as strlen
(to measure the string) or fputs
(to write the string to file).
A much easier shortcut might be to use fprintf
in the first place, and not need to allocate a separate buffer (it likely uses one built into FILE
) to store the formatted string.
It is possible, albeit not necessarily portable or safe, to convert between file descriptors (such as write
and close
use) and FILE
(such as fprintf
uses) using functions such as fdopen
.
Upvotes: 2