我非常喜欢%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);
代替(工作正常,我只是挑剔)
答案 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());