0

UPDATE according to TNTFreaks instructions answer.

I have a char variable data defined such as follow:

#define CMD_LEN 4
char data[CMD_LEN + 1];
float n1;

# I pass the data variable to `serial_read` function
n = serial_read(serial_fd, data, CMD_LEN, TIMEOUT);

# Here, the process goes to  serial_read function more below and
# after it return here again to follow ...


std::cout << "Data brought from serial_read method " << data << std::endl;

flush = tcflush(serial_fd, TCIOFLUSH);
//n = n*0.01f;

cout << "Applying sscanf " << std::endl;
sscanf(data, "%f", &n1);
printf("%.3f" "%s", n1, "  ");
n1 = atof(data) * 0.5f;
printf("%.3f", n1);
cout << "n1 value which have data turn it " << n1 << std::endl;

When the compiler check the serial_read function, enter to this process is:

*Note: I type this serial_read function only to illustration purposes in relation to workflow that follow my question in the process with respect to data variable *

    int SerialDriver::serial_read(int serial_fd, char *data, int size, int timeout_usec)
{
    std::cout << "Enter to serial_read method " << std::endl;
    fd_set fds;
    struct timeval timeout;
    bool band = false;
    int count = 0;
    int ret;
    int n;

    //-- Wait for the data. A block of size bytes is expected to arrive
    //-- within the timeout_usec time. This block can be received as
    //-- smaller blocks.
    do
    {
        //-- Set the fds variable to wait for the serial descriptor
        FD_ZERO(&fds);
        FD_SET(serial_fd, &fds);

        //-- Set the timeout in usec.
        timeout.tv_sec = 0;
        timeout.tv_usec = timeout_usec;
        // std::cout << "timeouts establecidos " << std::endl;

        //-- Wait for the data
        ret = select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
        //-- If there are data waiting: read it
        if (ret == 1)
        {
            //-- Read the data (n bytes)
            n = read(serial_fd, &data[count], 1);
            // read viene de sofa/src/applications/plugins/SofaPML/argumentParser.h
            std::cout << "Enter to read method to read hapkit data via serial port " << std::endl;

            if (band)
            {
                if (data[count] != ' ')
                {
                    if (data[count] == '\n')
                    {
                        data[count] = '\0';
                        return count;
                    }
                    //-- The number of bytes receives is increased in n
                    count += n;
                }
            }
            if (!band && data[count] == '\n')
            {
                band = true;
            }
            //-- The last byte is always a 0 (for printing the string data)
            data[count] = 0;
        }
        std::cout << "band value: " << band << " and data: " << data << std::endl;

        //-- Repeat the loop until a data block of size bytes is received or
        //-- a timeout occurs
    } while (count < size && ret == 1);

    //-- Return the number of bytes reads. 0 If a timeout has occurred.
    std::cout << "Leaving serial_read method " << std::endl;
    std::cout << "count value " << count << std::endl;
    return count;

}

When serial_read function finish, data is returned and have the char value like by example 1.86

I want to convert it that to float using atof() such as I type the code section at the beginning code of my question and store the result on n1 variable but the output that I get is:

Data brought from serial_read method 1.86
Applying sscanf 
1,000  0,500n1 value which have data turn it 0.5
Serial Driver draw n1: 0.5 1
1,000

The 1,000 value is the data value which I get that is 1.86, but atof remove the decimal parts or not include the foat data.

In summary is possible that I am not passing of a well way the parameter to atof function, (my n1 variable is float ). With respect to sscanf function, I am passing &n1 to sscanf like a a reference parameter to data to this be converted with atof, but this doesn't works

I get the same result. I was thinking that is possible, although I understand the TNTFreaks instructions I am not apply it of a correct way?

what am I doing wrong?

bgarcial
  • 2,915
  • 10
  • 56
  • 123
  • 5
    `char data="6.35";` won't compile. It's unclear what you are asking about. –  May 11 '18 at 22:09
  • 3
    The problem is your locale. See https://stackoverflow.com/questions/13919817/sscanf-and-locales-how-does-one-really-parse-things-like-3-14 – zdan May 11 '18 at 22:11
  • 1
    Are you sure you put the code into the question correctly? I get compilation errors whatever I do to the code: https://godbolt.org/g/GQ86Nk – Daniel H May 11 '18 at 22:13
  • 1
    Possible duplicate of [sscanf() and locales. How does one really parse things like "3.14"?](https://stackoverflow.com/questions/13919817/sscanf-and-locales-how-does-one-really-parse-things-like-3-14) – eyllanesc May 11 '18 at 22:29
  • Most implementations don't support it yet, but locale-independent parsing is now part of the C++17 standard library: http://en.cppreference.com/w/cpp/utility/from_chars. – Daniel H May 11 '18 at 22:38
  • @DanielH and @-NeilButterworth it's true, **I've updated** my answer in relation to the data value just in case. – bgarcial May 11 '18 at 22:38

1 Answers1

7

First of all, char is a type of variable that can only contain one or an array of characters not a string of characters. You may mean const char* data = "6.35" which is a c style string and what the atof() function requires as input. I would only use data as a const char* if you do not follow my recommendation below and still want to use sscanf() instead of cin.

In c++ using strings is easier than using const char* or char arrays. I would declare data as a string, get the input, and then convert it into a const char* using c_str() so atof() can use it.

atof returns a double not a float so you should declare n1 as a double.

I recommend not using a mixture of c and c++ commands (i. e. cout and sscanf()). It will compile in c++ if the syntax is correct, but I think it will be easier for you to use cin instead of sscanf().

You may also want to tell the compiler to assume the standard namespace (std) so you don't have to write std:: in front of all your cout's, cin's, endl's, etc.

Example:

#include <cstdlib> //atof
#include <iostream>   //cout, cin, endl
#include <string> //string, c_str()

using namespace std;   //now you don't have to write std::cout

int main() {
    float n1;
    string data;

    cin >> data;   //get input
    n1 = atof(data.c_str());   //convert data to const char* and make it a float
    cout << "Original data: " << data << endl;   //output
    cout << "Result: " << n1;
}

Updated, more intelligent, more useful answer:

These are just some things I took note of while doing some tests of my own.

  1. Don’t use double, use float. Double didn’t work in my research.
  2. When you used %.3f you were showing 3 decimal places of a whole number, hence why you get 6.000
  3. n1 = sscanf(data, "%f", n1) is not correct. It will compile, but the program should crash. (It did for me). First, sscanf() does not return the float found in data. It returns the number of variables filled so it will not result in what you intend. Second, n1 needs to be made a reference parameter for this to work. You want to edit the original variable n1 not make a copy of it. Correct syntax would be: sscanf(data, "%f", &n1);

Example:

#include <cstdlib>
#include <cstdio>

using namespace std;

int main() {
    char data[5] = "6.35";
    float n1;

    sscanf(data, "%f", &n1);
    printf("%.3f" "%s", n1, "  ");
    n1 = atof(data);
    printf("%.3f", n1);
    return 0;
}
PR06GR4MM3R
  • 397
  • 2
  • 13
  • The `sscanf` function is not just the C equivalent to `cin`, or anything like that. You could simplify `scanf` as that, but `sscanf` works on data already existing in the program memory, not on standard input. It's more like the equivalent of stringstreams, except stringstreams have quite a bit more runtime overhead in many (most? all?) cases. – Daniel H May 11 '18 at 22:42
  • declare data as a string it's a good idea, but the `char data` variable that I declare is of this way `char data[CMD_LEN + 1];` (**I've updated a few my question ... just in case please**), and this `data` variable is passed to `serial_read` function and here it's a pointer who receive this parameter. Then declare data like string it's not alternative for me ... :( – bgarcial May 11 '18 at 22:46
  • @bgarcial I lost my notes on this question, but I typed what I could remember. I will update more as I find things/remember them. – PR06GR4MM3R May 15 '18 at 01:55
  • @TNTFreaks if you need some information about it, I will be pending. – bgarcial May 15 '18 at 01:59
  • Hi @TNTFreaks I am follow the instructions that you orient me, but my result is the same applying `n1` like reference parameter to `sscanf(data, "%f", &n1);` My `atof` function does not convert to float the `data` value. **I've updated my question** about of that process of follow my `data` variable and I've trying check what is that happenning, but I ignore if I am applying well your instructions. Your support will be highly appreciated – bgarcial May 15 '18 at 17:20
  • Including "using namespace std;" is [considered bad](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice). – 1201ProgramAlarm May 18 '18 at 00:20
  • I am curious as to how/why the double didn't work in your research. I'll brush up on types but I'd still be interested in understanding why this happened. – Jouster500 May 23 '18 at 15:12
  • @Jouster500 me too actually – PR06GR4MM3R May 23 '18 at 15:28
  • @bgarcial the code worked for me. I will continue to look into this. Sorry I took so long to respond, I have had finals that finish today. – PR06GR4MM3R May 23 '18 at 15:30
  • @TNTFreaks of a separate way, the code works, but including with my serial_read function and the workflow process that I mention above, does not work. Your answer only it's works – bgarcial May 23 '18 at 19:46
  • @bgarcial hmmm. Ok then you may not be correctly diagnosing what part of your code is causing the problem. Can you provide a link for the full code? Google Drive or something ? – PR06GR4MM3R May 25 '18 at 04:13
  • On this file, I have the [serial_read](https://github.com/christiandiazleon/SimDesign_SOFA/blob/ZeroMQSerialComAllInOne/applications/plugins/ZeroMQCommunication/SerialDriver.cpp#L341) function which read data from serial port of some device connected. Next, the obtained data I want turn it on float, due to `serial_read ` function return it like `char` data type [here](https://github.com/christiandiazleon/SimDesign_SOFA/blob/ZeroMQSerialComAllInOne/applications/plugins/ZeroMQCommunication/SerialDriver.cpp#L354) and it's here in where `atof` doesm't works. – bgarcial May 27 '18 at 02:49
  • As additional data, I am using gcc 5.4.0 version C++ compiler. It's strange this, it seems that the standard c ++ libraries in this case `atof` does not works. I haven't another reason or explanation. – bgarcial May 27 '18 at 02:52
  • Hi @TNTFreaks I've replaced `atof` standard c++ library function by `stof` customized function which [is here](https://gist.github.com/bgarcial/5f8c64ed091f0ea7e5fa1361efddcc99#file-cpp-L7) and using `stof` instead `atof`, I get the decimal part. – bgarcial May 30 '18 at 22:26
  • Yes, now, perform the convert to char to float. – bgarcial Jun 03 '18 at 19:14
  • Explain further please. So is everything you need answered? @bgarcial – PR06GR4MM3R Jun 06 '18 at 01:17
  • [Here](https://gist.github.com/bgarcial/5f8c64ed091f0ea7e5fa1361efddcc99#file-cpp-L7) I've used the `stof` custom function which turn the `char` data to `float`. In my code, I use the `stof` function instead of `atof`: [I implement the stof function here](https://github.com/christiandiazleon/SimDesign_SOFA/blob/ZeroMQSerialCommDeformation/applications/plugins/ZeroMQCommunication/SerialDriver.cpp#L332) and I use the `stof` function of this [way](https://github.com/christiandiazleon/SimDesign_SOFA/blob/ZeroMQSerialCommDeformation/applications/plugins/ZeroMQCommunication/SerialDriver.cpp#L381) – bgarcial Jun 06 '18 at 20:31
  • For the moment that is all I need. – bgarcial Jun 06 '18 at 20:31