% s не будет работать со строкой

Мне очень нравится концепция% 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 внутри функции запуска (при проверке соединения) фактически получает% s, а не значение пароля / информации о сервере

Он просто отображается в консоли как «PASS% s» или «SERVER% s» — как я уже сказал, мне нравится концепция% s, есть ли другой способ реализовать это или просто использовать send_cmd("PASS",PASSWORD); вместо этого (который работает хорошо, я просто привередлив)

0

Решение

У вас есть несколько возможностей здесь. Один из них — немного изменить существующую функцию, использовать 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 должно работать нормально.

5

Другие решения

Вы можете использовать sprintf для преобразования в символьную строку, а затем изменить send_cmd, чтобы иметь только два параметра.

1

Вы можете использовать библиотеку формата Boost для подготовки вашего вывода — 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());
0
По вопросам рекламы [email protected]