【问题标题】:C++ , return string from function; boost::asio read / writeC++,从函数返回字符串; boost::asio 读/写
【发布时间】:2014-12-31 04:58:11
【问题描述】:

我得到一个编译错误,另外我不能在不给它数组元素的情况下 boost::asio::read buf。

std::string eport::read_data (void)
{
    io_service io;  // create the I/O service that talks to the serial device
    serial_port port (io, PORT);    // create the serial device, note it takes the io service and the port name
    error_code ec;  // address used for error checking
    std::string buf [100];  // data with crc on end

    try
    {
        read (port, buffer (buf), ec);
        std::cout << "eport::read: result: " << buf << std::endl;
    }
    catch (error_code &ec)
    {
        std::cout << "eport::read: ERROR: " << ec << std::endl; 
        return "error";
    }

    std::cout << "eport::read: SUCCESS" << std::endl;

    return buf;

错误:

eport.cc:83:9: error: could not convert ‘(std::string*)(& buf)’ from ‘std::string* {aka std::basic_string<char>*}’ to ‘std::string {aka std::basic_string<char>}’

函数是否需要转换为 const char* ?我不确定出了什么问题。任何帮助表示赞赏,谢谢。

更新代码

这是我的代码。我希望它可以帮助某人,因为 asio 在网络上缺乏好的例子。我知道我的 write 函数可以写得更好,而且这段代码还没有经过测试,所以我不确定我这样做是否正确。谢谢。

#include "../include/main.H"
#include <boost/asio.hpp>   // asynchronous input/output
#include <boost/crc.hpp>    // cyclic redundancy code (for data checking)

using namespace::boost::system;
using namespace::boost::asio;

const char *PORT = "/dev/ttyS0";

// serial port communication setup
serial_port_base::baud_rate BAUD (9600);    // what baud rate do we communicate at (default is 9600)
serial_port_base::character_size C_SIZE (8);    // how big is each "packet" of data (default is 8 bits)
serial_port_base::flow_control FLOW (serial_port_base::flow_control::none); // what flow control is used (default is none)
serial_port_base::parity PARITY (serial_port_base::parity::none);   // what parity is used (default is none)
serial_port_base::stop_bits STOP (serial_port_base::stop_bits::one);    // how many stop bits are used (default is one)

int eport::initialize (void)
{
    io_service io;  // create the I/O service that talks to the serial device
    serial_port port (io, PORT);    // create the serial device, note it takes the io service and the port name

    // set serial port options
    port.set_option (BAUD);
    port.set_option (C_SIZE);
    port.set_option (FLOW);
    port.set_option (PARITY);
    port.set_option (STOP);

    return 0;
}

int eport::write_data (std::string data)
{
    io_service io;  // create the I/O service that talks to the serial device
    serial_port port (io, PORT);    // create the serial device, note it takes the io service and the port name
    error_code ec;  // address used for error checking
    boost::crc_32_type crcresult;   // used for communication checking
    char buf [1024];    // buffer to hold data
    int crc;    // holds crc value
    std::ostringstream convert; // used to convert int to string
    std::string data_crc;   // data with crc on end
    std::stringstream ss;   // used to add strings

    strncpy (buf, data.c_str(), sizeof(buf));   // put data into buffer
    buf [sizeof(buf) - 1] = 0;  // make sure the last element has a null

    crcresult.process_bytes (buf, sizeof(buf)); // get crc value from buffer contents
    crc = crcresult.checksum(); // put crc value into integer
    convert << crc; // convert integer to string
    ss << data << convert.str ();   // add crc string to data string
    data_crc = ss.str ();   // data string with crc appended to be used in reading / writing
    std::cout << "eport::write: data with crc: " << data_crc << std::endl; 

    std::cout << "eport::write: writing: " << data_crc << std::endl; 
    write (port, buffer (data_crc, sizeof(data_crc)), ec);  // write data with crc to serial device

    if (ec) // if error code is true, print and return
    {
        std::cout << "eport::write: ERROR: " << ec << std::endl; 
        return -1;
    }

    std::cout << "eport::write: SUCCESS" << std::endl;

    return crc;
}

std::string eport::read_data (void)
{
    io_service io;  // create the I/O service that talks to the serial device
    serial_port port (io, PORT);    // create the serial device, note it takes the io service and the port name
    error_code ec;  // address used for error checking
    streambuf sb;   // asio stream buffer to hold read data
    std::string buf;    // read buffer will be put into this string

    size_t transferred = read (port, sb, ec);   // read data from serial device
    buf.resize (transferred);   // resize the string to the read data size
    sb.sgetn (&buf[0], buf.size ());    // stores characters from the stream to the array
    std::cout << "eport::read: result: " << buf << std::endl;

    if (ec)
    {
        std::cout << "eport::read: ERROR: " << ec << std::endl; 
        return "error";
    }

    std::cout << "eport::read: SUCCESS" << std::endl;

    return buf;
}

【问题讨论】:

  • 在您的read 函数中,您如何知道实际读取的字符数?这是您的代码中的一个漏洞,您需要先解释一下,然后才能给出一个好的答案。
  • @MattMcNabb boost::asio::buffer 适配器函数

标签: c++ string boost boost-asio


【解决方案1】:
  1. 最通用的方法是使用asio::streambuf

    streambuf sb;
    size_t transferred = read (port, sb, ec);
    

    根据文档:

    该函数用于从流中读取一定字节数的数据。调用将阻塞,直到满足以下条件之一:

    • 提供的缓冲区已满(即已达到最大大小)。
    • 发生错误。

    此操作是根据对流的read_some 函数的零次或多次调用来实现的。

    然后,将其复制到一个字符串中:

    std::string buf;
    buf.resize(transferred);
    sb.sgetn(&buf[0], buf.size());
    

  2. 或者,预分配预期大小的缓冲区:

    std::string buf(100u, '\0');
    size_t transferred = read (port, buffer(buf), ec);
    buf.resize(transferred);
    

  3. 对于更复杂的场景,使用read_until

    streambuf sb;
    size_t transferred = read_until(port, sb, "\r\n", ec);
    

    这将一直读取到遇到"\r\n"(注意:可能会读取更多,但在看到分隔符后不会再次调用read_some)。


  4. 更复杂的停止条件可以使用overload that takes a MatchCondition functor

异常处理注意事项

如果您通过ec 接收error_code,则不会抛出异常

【讨论】:

  • 聪明的答案。我将使用您的第一种方法,它对我来说编译得很好。完成后我会发布我更新的程序。谢谢。
【解决方案2】:

bufstd::string 的数组。您应该更改原型或只返回一个字符串。以buf[0] 为例。

很可能你想要的是:

std::string buf;  // No [100]

【讨论】:

  • 是的,你是对的,谢谢;出于某种原因,我认为每个元素都包含一个像 char 数组一样的字符,但是每个字符串元素都可以包含很多文本,对吧?
  • 是的,你是对的。检查Example
  • 说得通;但是缓冲区(buf)给了我编译错误;也许我会为此创建一个单独的变量并将其放入字符串中
  • 在这种情况下,您应该使用unsigned char buf[MAX_BUF_SIZE];std::vector&lt;unsigned char&gt; buf(MAX_BUF_SIZE); 并将&amp;buf[0] 作为读取参数传递。
  • 根据其他 API 的要求和性质,一种形式可能或多或少优于另一种形式。
【解决方案3】:

您的代码存在需要回答的问题,更具体地说,您如何知道将发送到您的read 函数的字符数?

但是,您的问题的一般答案是使用字符数组,然后将其作为 std::string :

std::string eport::read_data (void)
{
    io_service io;  // create the I/O service that talks to the serial device
    serial_port port (io, PORT);    // create the serial device, note it takes the io service and the port name
    error_code ec;  // address used for error checking
    char buf [100];  // data with crc on end

    try
    {
        read (port, buf, ec);
        std::cout << "eport::read: result: " << buf << std::endl;
    }
    catch (error_code &ec)
    {
        std::cout << "eport::read: ERROR: " << ec << std::endl; 
        return "error";
    }

    std::cout << "eport::read: SUCCESS" << std::endl;

    return buf;
}

std::string 构造函数将负责将末尾的 buf 复制到 std::string。

现在,如果有办法确定读取的字符数,那么函数必须以不同的方式编写。大多数read 函数都有一个参数指定要读取的最大字符数,并在某处返回读取的字符数。

假设您可以重写(或调用)具有这两个属性的不同读取函数,代码将如下所示:

std::string eport::read_data (void)
{
    io_service io;  // create the I/O service that talks to the serial device
    serial_port port (io, PORT);    // create the serial device, note it takes the io service and the port name
    error_code ec;  // address used for error checking
    char buf [100];  // data with crc on end
    int numCharsRead = 0;
    try
    {
        numCharsRead = read2 (port, buf, 100, ec);
        std::cout << "eport::read: result: " << buf << std::endl;
    }
    catch (error_code &ec)
    {
        std::cout << "eport::read: ERROR: " << ec << std::endl; 
        return "error";
    }

    std::cout << "eport::read: SUCCESS" << std::endl;

    return std::string(buf, numCharsRead);
}

注意return 的区别。 std::string 从字符数组构造,但最多只能有 numCharsRead 个字符。

【讨论】:

  • 好的,我不知道它会自动执行,谢谢;我认为 boost::asio::read 将结果放入 buf
  • 我应该把它变大,1024;并做 buf.length() 看看有多大?
  • 没有真正需要“发明”其他 API,例如 read2。可用的 API 已记录在案(请参阅我的回答)
猜你喜欢
  • 2014-11-06
  • 2011-05-29
  • 2021-04-16
  • 2013-03-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多