Код выдает Segmentation Fault, почему?
#include<iostream>
#include<boost/asio.hpp>
#include<boost/array.hpp>
using tcp=boost::asio::ip::tcp;
int main()
{
boost::asio::io_service io_service;
tcp::endpoint endpoint(tcp::v4(),9999);
tcp::acceptor accept(io_service,endpoint);
tcp::socket socket(io_service);
accept.accept(socket);
std::string message="Hello";
int readedByte=0;
for(;;)
{
int readByte=socket.write_some(boost::asio::buffer(&message+readedByte,sizeof(message)));
readedByte=readedByte+readByte;
if(readedByte==sizeof(message))
{
break;
}
}
return 0;
}
Это код сервера
А вот код клиента кидает Segmentation fault
#include<boost/asio.hpp>
#include<boost/array.hpp>
#include<iostream>
using tcp=boost::asio::ip::tcp;
int main()
{
boost::asio::io_service io_service;
tcp::endpoint endpoint;
endpoint.port(9999);
endpoint.address(boost::asio::ip::address_v4::from_string("127.0.0.1"));
tcp::socket socket(io_service);
socket.connect(endpoint);
std::string req{""};
int readedByte=0;
for(;;)
{
int readByte=socket.read_some(boost::asio::buffer(&req+readedByte,128));
readedByte=readedByte+readByte;
if(readedByte==sizeof(std::string{"Hello"}))
{
break;
}
}
return 0;
}
В чем дело?
Ответы (1 шт):
Прерывание поднимается из-за того, что &req+readedByte указывает на нелегальную область памяти. &req - это указатель на объект типа string, &req+readedByte - указатель на readedByte-й элемент массива string-ов,следующий за &req. Такого масива тут нет. &message+readedByte тоже нелегален, но тут серверу "повезло".
Указывать на сам класс сторки нельзя - это не та область памяти, где хранятся данные (обычно там внутри есть указатель на реальный буфер). К тому же строку нельзя использовать для записи напрямую, для этого следует воспользоваться чем-то похожим на вектор как промежуточным буфером.
Вот такой простой пример, почему лучше не пользоваться строкой:
#include <iostream>
#include <cstring>
int main()
{
std::string str1 = "Hello, End of line!";
const char *str2 = "Hello!";
std::strcpy(&str1[0], str2); // C++17 - можно str.data()
std::cout << str1 << std::endl;
}
strcpy() копирует терминирующий символ, не так ли? Строка str1 имела длину больше чем новая строка, значит все в порядке и вывод будет "Hello!"?
Отнюдь, скорее всего вывод будет таким:
Hello!End of line!
Длина строки осталась прежней, length() вернет 19. Даже параноидальное std::memcpy(&str1[0], str2, strlen(str2)+1); не поможет. Как видно, ноль "съел" пробел, но вся подсистема игнорирует наличие нулевого символа.
std::string не нуль-терминированная строка и вовод в данном случае осуществляется не с использованием символа-терминатора. Это только data() гарантированно возвращает указатель на нуль-терминированную последовательность если CharT является char. Как string отслеживает свою длину, одному string-у известно. В данном случае
`str1.resize(strlen(str2));`
исправит положение?.. Получается что мы точно должны знать сколько символов было записано и обновить состояние "буфера" чтобы его отобразить корректно.
std::string str1;
const char *str2 = "Hello!";
str1.resize(strlen(str2)); // так можно?
std::strcpy(str1.data(), str2);
std::cout << str1 << std::endl;
Можно так? Вроде можно.. постойте, а куда в данном случае strcpy ноль пишет? Конечно, может и не упасть, если строка выделила больше памяти. str1.resize(strlen(str2)+1) в данном случае менее рискованно, хотя тоже неправильно, ноль станет частью строки.
str1.resize(strlen(str2));
std::memcpy(str1.data(), str2);