표준 정보는 여기서 봅시다.
https://cplusplus.com/reference/sstream/stringstream/
https://en.cppreference.com/w/cpp/io/basic_stringstream
문자열 스트림 (std::stringstream)
마치 문자열을 하나의 스트림이라 생각하게 해주는 가상화 장치
sstream에는 std::istringstream 이 정의되어 있는데 이는 문자열을 하나의 스트림으로 생각하게 해주는 가상화 장치 입니다.
std::istringstream 을 통해서 123 을 읽어낼 수 있습니다.
이를 활용하면 atoi 와 같은 함수를 사용할 필요 없이 간편하게 문자열에서 숫자로 변환하는 함수를 만들 수 있습니다.
스트림에서 데이터를 가져오는 방법
스트림에서 데이터를 갖고 오는 방법은 여러가지가 있다.
스트림의 텍스트 모드
스트림 상의 데이터를 바이트 단위로 읽어서 Whitespace 단위로 끊은 뒤에 원하는 타입으로 읽어오는 방법.
std::stringstream :스트림의 텍스트 모드를 이용하면 단순히 nan, inf와 같은 입력을 받아도 이를 명확하게 실수로 변환할 수 있고, 그 외의 문자로 입력을 받은 경우에는 수로 인식을 하지 못하여 이를 따로 처리하는 것도 가능하다.
std::istream_iterator<T>를 사용하면 Whitespace를 손실하게 되지만, 여러 개의 입력 값을 원하는 타입으로 얻어낼 수 있다.
스트림의 바이너리 모드
스트림에서 데이터를 바이너리 단위로 읽어서 문자 타입으로 읽을 수도 있다.
istreambuf_iterator<T>는 스트림의 파일 버퍼에 직접 접근할 수 있고, 텍스트 모드와 달리 바이트 단위의 변환이 없기 때문에 istream_iterator<T>보다 빠르게 작업을 처리할 수 있다.
사용 방법
- clear() : 스트림을 지웁니다.
- str() : 콘텐츠가 스트림에 있는 문자열 개체를 가져오고 설정합니다.
- operator << : stringstream 개체에 문자열을 추가합니다.
- 연산자 >> : tringstream 객체에서 무언가를 읽습니다.
예시1 (string to int)
#include <iostream>
#include <sstream>
int main() {
std::istringstream ss("123");
int x;
ss >> x;
std::cout << "입력 받은 데이터 :: " << x << std::endl;
return 0;
}
예시2 (int to string)
#include <iostream>
#include <sstream>
#include <string>
std::string to_str(int x) {
std::ostringstream ss;
ss << x;
return ss.str();.//이건 int형을 문자열로 쉽게 바꿀수 있다. 신기하다.!!!
}
int main() {
std::cout << "문자열로 변환:: 1 + 2 = " << to_str(1 + 2) << std::endl;
return 0;
}
예시 3 (Dex to Hex)
#include <bits/stdc++.h>
using namespace std;
int main()
{
int i = 942;
stringstream ss;
ss << hex << i;
string res = ss.str();
cout << "0x" << res << endl; // this will print 0x3ae
return 0;
}
예시 4(Hex to Dex)
#include <bits/stdc++.h>
using namespace std;
int main()
{
string hexStr = "0x3ae";
unsigned int x;
stringstream ss;
ss << std::hex << hexStr;
ss >> x;
cout << x << endl; // this will print 942
return 0;
}
파일 스트림에서 버퍼를 효율적으로 사용하는 방법
std::ifstream 에서 파일을 읽어올 때 iterator은 파일 탐색을 기반으로 하기 때문에 파일 디스크의 버퍼를 계속해서 불러와야만 한다. 이는 상당히 큰 단점으로 작용한다. 따라서 만약 여러번 파일을 읽어오는 경우에는 파일 스트림이 가지고 있는 버퍼의 내용을 메모리 상으로 옮겨서 작업을 해야한다.
이것이 가능하게 해주는 것이 std::stringstream이다.
std::ifstream의 데이터를 std::stringstream 으로 가져올 때는 itreator(<< , >>) 를 활용해도 된다.
그외의 방법으로는 스트림간의 데이터 이동에서만 사용할 수 있는 방법인데 rdbuf라는 멤버 함수를 이용하면 한번에 데이터를 옮기는 것이 가능하다.
rdbuf함수
basic_filebuf라는 객체의 주소를 반환하는데 이를 << 라는 삽입 연산자와 함께 사용하면 한 번에 입력할 수 있다.
#include <iostream> // std::cout
#include <fstream> // std::filebuf, std::ifstream
#include <sstream>
int main () {
std::ifstream ifs ("test.txt", std::ifstream::binary);
// get pointer to associated buffer object
std::filebuf* pbuf = ifs.rdbuf();
//std::cout << pbuf;
std::stringstream ss ;
ss << pbuf;
int a ;
ss >> a;
std::cout << a;
}
예시 코드를 보면 이해가 쉬울 것 같다. 직접 조작해보면서 익히도록 하자.
stream으로 입력을 받을 때 문제점
overflow와 underflow에 대해서 제대로 대응하기 어렵다. 만약 그것에 대해서 대응하고 싶다면 std::stoi, std::stof, std::stod 등 함수들이 그 역활을 수행 할 수 있을 것이다.
소수점 아래 리터럴 표기가 있는 경우 처리
기본적으로 stream data로 문자를 받을 때 1..1… 이런식으로 입력을 받게 되면, 정상적으로 처리를 하지 못하는 단점이 있었다. 따라서 이 문제를 해결하려면 std::atof 혹은 std::strtod 함수를 사용하면 된다.
std::atof vs std::strtod
atod함수는 double표현범위를 벗어나면 undefine되어있으나, std::strtod같은 경우, 범위를 벗어나도 errno 역시 ERANGE로 설정이 되고 , HUGE_VAL을 반환해서 조금 std::strtod함수가 더 좋은 함수임을 알 수가 있다.
std::isnan & std::isinf
스트림에서 뽑아낸 형변환이 nan인지 inf인지도 구분하려면 <cmath>의 std::isnan, std::isinf를 이용하여 알아낼 수 있다. cpprefence 혹은 cplusplus에서 검색해보면 두 함수가 C++11인 것을 볼 수 있는데, C99 버전의 isnan과 isinf가 <cmath>에도 존재합니다. 두 함수는 모두 매크로 함수를 호출하는 함수이다. C99 버전의 <cmath>는 C++98에 완전한 호환성을 가진다.
std::showpos
부호를 출력해주는 설정이다.
std::cout << std::showpos << 1
이렇게 입력을 해보면, +1 이 나오는 것을 알 수가 있다.
'CPP' 카테고리의 다른 글
[Cpp 개념공부]표준스트림과 입출력 (0) | 2023.03.04 |
---|---|
[cpp개념공부]클래스 멤버 포인터 , 함수 포인터(CPP Module02) (5) | 2023.02.28 |
[cpp개념공부] throw ,try-catch (2) | 2023.02.18 |
[c++ 개념공부] virtual 소멸자,가상함수 테이블, 다중상속, 가상상속 (0) | 2023.02.11 |
[cpp개념공부] 가상함수와 업 캐스팅 (0) | 2023.02.11 |