%s不能使用字符串

时间:2013-06-26 02:47:37

标签: c++ string irc

我非常喜欢%s,ID的概念。我注意到这适用于char,我知道这是一个C风格的功能。我想知道是否有任何其他方式用字符串实现%s:

继承我的代码:

#include "services.h"

#include <iostream>
using namespace std;

services::services()
{
}


services::~services()
{
}

int services::startup()
{

#if defined(WINDOWS)
    {
        WSAData data;

         if(WSAStartup(MAKEWORD(2,2), &data) != 0)
             exit(1);
    }
#endif

    int addresssize = sizeof(address);

    address.sin_addr.s_addr = inet_addr("69.60.118.163");
    address.sin_family = AF_INET;
    address.sin_port = htons(6667);

    sock = socket(AF_INET,SOCK_STREAM,0);

    if(sock < 0)
        return -1;

    string PASSWORD = "password1";
    string SERVER_NAME = "admin.services.net";
    string SERVER_DESC = "Administration IRC Services";


    if(connect(sock,(struct sockaddr *)&address,addresssize) == 0)
    {
        send_cmd("PASS ","%s\n",PASSWORD);
        send_cmd("SERVER ","%s 1 %s\n",SERVER_NAME,SERVER_DESC);

     return 0;
    }

    return -1; //ooops
}

void services::parseData()
{
    char buffer[512];
    stringstream convert;
    string newbuffer;
    for(;;)
    {
        int index = recv(sock,buffer,512-1,0);
        buffer[index]='\0';
        newbuffer = buffer;

        cout << newbuffer.c_str() << endl;

        if(index == 0)
        {
            cout << "Connection was closed!" << endl;
            break;
        }

        system("pause");

    }
}

void services::send_cmd(string cmd)
{



}

void services::send_cmd(string cmd, string param,...)
{
    int bufsize;
    string newmsg;

        newmsg = (cmd += param);

        cout << newmsg.c_str() << endl;

        bufsize = sizeof(newmsg);

        send(sock,newmsg.c_str(),strlen(newmsg.c_str()),0);
}

现在问题是send_cmd int他启动函数(在连接检查中)实际上是%s而不是密码/服务器信息的值

它只是在控制台中显示为“PASS%s”或“SERVER%s” - 正如我所说我喜欢%s的概念是否还有其他方法可以实现这一点,或者仅使用send_cmd("PASS",PASSWORD);代替(工作正常,我只是挑剔)

3 个答案:

答案 0 :(得分:5)

你有几种可能性。一个是稍微修改你现有的函数,使用vsprintf,所以它可以接受任意数量的参数并做printf之类的替换:

void services::send_cmd(string cmd, char const *param,...)
{
    char buffer[512];

    va_list args;
    va_start(param, args);
    vsprintf(buffer, args, param);
    va_end(args);
    cmd += buffer;
    send(sock, cmd.c_str(),cmd.length(),0);
}

这与使用变量参数列表的所有函数共享一个问题:将std::string(或任何其他非POD类类型的对象)作为变量参数之一传递会导致未定义的行为。

如果您希望能够通过std::string,您还有其他几种可能性。更简单的方法是使用流将数据写入套接字。为此,您将编写一个(幸运的是,相当简单的)流缓冲类,它将数据写入套接字而不是像磁盘上的文件那样更典型的目标。这不是非常很难做到,但是当我甚至不确定你想要它时,发布肯定太多了。

第三种可能性是使用可变参数模板来支持各种类型的处理参数。这消除了必须传递格式字符串,因为它可以直接从参数中推断出类型:

#include <sstream>
#include <string>
#include <iostream>

template <class T>
std::string stringify(T const &t) { 
    std::stringstream b;
    b << t;
    return b.str();
}

template<typename T, typename... Args>
std::string stringify(T arg, const Args&... args) {
    return stringify(arg) + stringify(args...);
}

template<typename... Args>
void send_cmd(const Args&... args) { 
    std::string buffer = stringify(args...);
    send(sock, buffer.c_str(), buffer.length(), 0);
}

int main() {
    std::string three{" three"};

    send_cmd("one: ", 1, " two: ", 2, three, "\n");

    return 0;
}

使用C ++ 17,可以使用折叠表达式大大简化,所以它变成这样:

template<typename... Args>
void send_cmd(int sock, const Args&... args) {
    std::ostringstream os;
    (os << ... << args);
    std::string const &s = os.str();
    send(sock, s.c_str(), s.length(), 0);
}

int main() {
    std::string three{ " three" };

    int x = socket();

    // Of course, here you'll need to connect the socket to use it.

    send_cmd(x, "one: ", 1, " two: ", 2, three, "\n");

    return 0;
}

我在演示代码中传递了一些字符串文字,整数和一个std::string,但基本上支持cout << whatever之类的任何类型都可以正常工作。

答案 1 :(得分:1)

您可以使用sprintf转换为字符串,然后将send_cmd修改为只有两个参数。

答案 2 :(得分:0)

您可以使用提升格式库来准备输出 - http://www.boost.org/doc/libs/1_53_0/libs/format/doc/format.html - 类似于:

send_cmd("SERVER ", format("%1% 1 %2%\n", SERVER_NAME, SERVER_DESC).str());