odd
odd

Reputation: 141

Convert float into String and send from C code to Python through Named Pipe

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

Answers (3)

odd
odd

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

KamilCuk
KamilCuk

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

Yann Vernier
Yann Vernier

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

Related Questions