C++ IOS API에서 유용하다 싶은 부분을 주관적으로 작성한 문서입니다.
- cin, wcin, cout, wcout
- boolalpha
- setprecision, precision
- showpoint
- showpos
- showbase
- uppercase
- dec, hex, oct
- fixed, scientific, hexfloat, defaultfloat
- width
- fill
- left, right, internal
cin, wcin, cout, wcout[top]
extern std::ostream cout;extern std::wostream wcout;extern std::istream cin;extern std::wistream wcin;
- 위의 네 가지는 전역 변수로서 C 내의 입출력 스트림(in/out stream)을 다룹니다.
std::streambuf타입을 상속받은 스트림 버퍼와 큰 관련이 있는데, 입력시 cin은 스트림 버퍼로부터 입력값을 가져오며, 출력시 cout은 출력값을 스트림 버퍼로 전달합니다. - 위의 네 가지 객체는
std::ios_base::Init이라는 객체가 처음 초기화 되는 중 혹은 되기 이전에 생성되는 것을 보장합니다. 이는 즉 우리 프로그래머들이 정적(혹은 전역) 변수를 생성/파괴 할 때, 즉 프로그램이 시작될 때와 종료될 때 cin/cout을 포함한 네 개의 객체를 문제없이 사용할 수 있음을 의미합니다.- (해당 정적 객체가 정의되기 전에 헤더가 선언되어 있는 경우에 한합니다.)
sync_with_stdio(false)가 설정되어 있지 않다면 스레드 안전성이 보장됩니다.- cout/wcout 이 생성되는 시기에 cin/wcin 과
tie()를 통해 묶이게 됩니다. 이런 특징탓에 만약 특정 입력 명령이 cin/wcin 을 통해 수행된다면 cout/wcout 에는 자동적으로cout.flush()가 호출됩니다.
#include <iostream>
struct Foo {
Foo() {
std::cout << "static constructor, Enter Interger : ";
std::cin >> n;
}
~Foo() {
std::cout << "static destructor\n";
}
int n;
};
Foo f; // static object
int main()
{
std::cout << "main function, f.n : " << f.n << "\n";
}정적 변수의 생성자/소멸자에서 cin/cout 를 활용해 입출력 명령을 호출합니다. 해당 명령은 프로그램이 시작될 때/ 종료될 때 호출되지만 실행에 있어 문제되는 건 없습니다. cin/ cout 객체는 해당 시점에 안전하게 사용될 수 있음이 보장됩니다.
static constructor, Enter Interger : 7
main function, f.n : 7
static destructor- 추가적으로 cout과 printf 의 차이
- cout 은 std::ostream 전역 객체에 대해 지속적으로 연산자 오버로딩 함수를 호출하는 반면, printf는 format 문자열에 상응하는 argument를 입력받는 형태입니다. printf 의 format 을 활용하는 방식에 대해서 type safety가 언급되고 있는데, format 타입과 argument 타입이 다를 경우 컴파일러에 따라 오류/경고 메세지를 출력하는 방식이 다르며 이 부분은 개발자들에게 혼란을 줄 수 있다는 것입니다. 반면에 cout의 연산자 오버로딩은 매개변수의 타입별로 오버로딩 함수를 제공할 수 있으니 좀더 type safety 가 보잗된다고 말해집니다.
- cout 의 경우 ios flag를 활용해 출력 형태를 임의로 지정할 수 있습니다.
- 속도의 경우 printf가 빠르다는 인식이 널리 퍼져 있지만, 실제로는 케바케라고 합니다.(아래의 스택 오버플로우 링크 참조)
- cin과 scanf의 성능차이
- 일반적으로는 scanf가 빠릅니다만,
std::ios::sync_with_stdio(false);을 설정해서 스레드 안전성을 포기하고 대신 오버헤드를 줄인다면, cin이 더 빠르다고 합니다.
- 일반적으로는 scanf가 빠릅니다만,
- cppreference : cin
- cppreference : cout
- stackoverflow : 'printf' vs. 'cout' in C++
- stackoverflow : using-scanf-in-c-programs-is-faster-than-using-cin
boolalpha[top]
- 입출력시 bool 타입을 정수형 혹은 문자열로 다룰 것인지 지정합니다.
str.setf(std::ios_base::boolalpha),str.unsetf(std::ios_base::boolalpha)을 통해 특정 입출력스트림str의 ios 형식 플래그를 지정 가능합니다.- cppreference : boolalpha
#include <iostream>
void main() {
std::cout << std::boolalpha << true << ", " << false << std::endl;
std::cout << std::noboolalpha << true << ", " << false << std::endl;
}true, false
1, 0precision[top]
- 입출력시 부동수소점의 정밀도 수준을 지정합니다.
- cppreference : precision
- cppreference : setprecision
#include <iostream>
#include <iomanip>
void main() {
const long double pi = std::acos(-1.L);
const auto maxPrecisionLength = std::numeric_limits<long double>::digits10 + 1;
std::cout << "default precision (6): " << pi << '\n';
std::cout << "std::setprecision(10): " << std::setprecision(10) << pi << '\n';
std::cout << "max precision: : " << std::setprecision(maxPrecisionLength) << pi << '\n';
}default precision (6): 3.14159
std::setprecision(10): 3.141592654
max precision: : 3.141592653589793#include <iostream>
int main()
{
const double d = 1.2345678901234;
std::cout << "The default precision is " << std::cout.precision() << "\n\n";
std::cout << "With default precision d is " << d << '\n';
std::cout.precision(12);
std::cout << "With high precision d is " << d << '\n';
}The default precision is 6
With default precision d is 1.23457
With high precision d is 1.23456789012showpoint[top]
- 부동소수점 출력시(입력은 영향 없음) 수소점 뒷자리 표현 여부를 지정합니다. 예시에서 보시다시피, 이미 수소점 뒤의 값이 0이 아니라면 noshowpoint 를 지정해도 소수점 뒷자리가 출력되는 것을 보실 수 있습니다.
str.setf(std::ios_base::showpoint),str.unsetf(std::ios_base::showpoint)을 통해 특정 입출력스트림str의 ios 형식 플래그를 지정 가능합니다.- cppreference : showpoint
#include <iostream>
int main()
{
std::cout << "1.0 with showpoint : " << std::showpoint << 1.0 << '\n';
std::cout << "1.0 with noshowpoint: " << std::noshowpoint << 1.0 << '\n';
const auto pi = std::acos(-1.L);
std::cout << "pi with showpoint : " << std::showpoint << pi << '\n';
std::cout << "pi with noshowpoint : " << std::noshowpoint << pi << '\n';
}1.0 with showpoint : 1.00000
1.0 with noshowpoint: 1
pi with showpoint : 3.14159
pi with noshowpoint : 3.14159showpos[top]
- 출력시(입력은 관계 없음) 양수 값에 대해
+부호 출력여부를 지정합니다. - cppreference : showpos
#include <iostream>
int main()
{
std::cout << "showpos : " << std::showpos << 42 << ' ' << 3.14 << ' ' << 0 << ' ' << -1 << ' ' << -37.1342 << '\n';
std::cout << "noshowpos: " << std::noshowpos << 42 << ' ' << 3.14 << ' ' << 0 << ' ' << -1 << ' ' << -37.1342 << '\n';
}showpos : +42 +3.14 +0 -1 -37.1342
noshowpos: 42 3.14 0 -1 -37.1342showbase[top]
- 출력시(입력은 관계 없음) 정수 표현식의 접두사(hex 표현식의 0x 등) 의 출력 여부를 지정할 수 있습니다.
- 입출력시 화폐 출력 표현 및 입력 분석 형식을 지정할 수 있습니다.
str.setf(std::ios_base::showbase),str.unsetf(std::ios_base::showbase)을 통해 특정 입출력스트림str의 ios 형식 플래그를 지정 가능합니다.- cppreference : showbase
#include <iostream>
int main()
{
std::cout << "showbase : " << std::hex << std::showbase << 42 << '\n';
std::cout << "showbase : " << std::oct << std::showbase << 42 << '\n';
std::cout << "noshowbase: " << std::hex << std::noshowbase << 42 << '\n';
std::cout << "noshowbase: " << std::oct << std::noshowbase << 42 << '\n';
}showbase : 0x2a
showbase : 052
noshowbase: 2a
noshowbase: 52uppercase[top]
- 입출력시 대소문자 형식을 지정합니다.
str.setf(std::ios_base::uppercase),str.unsetf(std::ios_base::uppercase)을 통해 특정 입출력스트림str의 ios 형식 플래그를 지정 가능합니다.- cppreference : uppercase
#include <iostream>
int main()
{
std::cout << std::hex << std::showbase;
std::cout << "0x2a with uppercase: " << std::uppercase << 0x2a << '\n';
std::cout << "0x2a with nouppercase: " << std::nouppercase << 0x2a << '\n';
std::cout << "1e-10 with uppercase: " << std::uppercase << 1e-10 << '\n';
std::cout << "1e-10 with nouppercase: " << std::nouppercase << 1e-10 << '\n';
}0x2a with uppercase: 0X2A
0x2a with nouppercase: 0x2a
1e-10 with uppercase: 1E-10
1e-10 with nouppercase: 1e-10dec, hex, oct[top]
- 입출력시 정수형 표현식을 지정합니다.
str.setf(std::ios_base::dec, std::ios_base::basefield),str.setf(std::ios_base::hex, std::ios_base::basefield),str.setf(std::ios_base::oct, std::ios_base::basefield)을 통해 특정 입출력스트림str의 ios 형식 플래그를 지정 가능합니다.- cppreference : hex
#include <iostream>
int main()
{
std::cout << "The number 42 in octal : " << std::oct << 42 << '\n';
std::cout << "The number 42 in decimal : " << std::dec << 42 << '\n';
std::cout << "The number 42 in hex : " << std::hex << 42 << '\n';;
}The number 42 in octal : 52
The number 42 in decimal : 42
The number 42 in hex : 2a#include <iostream>
#include <sstream>
int main()
{
int n;
std::istringstream("2a") >> std::hex >> n;
std::cout << std::dec << "Parsing \"2A\" as hex : " << n << '\n';
std::cout << std::hex << "Print \"42\" as hex : " << 42 << '\n';
std::istringstream("2a") >> std::dec >> n;
std::cout << std::dec << "Parsing \"2A\" as dec : " << n << '\n';
}Parsing "2A" as hex : 42
Print "42" as hex : 2a
Parsing "2A" as dec : 2fixed, scientific, hexfloat, defaultfloat[top]
- 입출력시 부동소수점 표현식을 지정합니다.
str.setf(std::ios_base::fixed, std::ios_base::floatfield),str.setf(std::ios_base::scientific, std::ios_base::floatfield)을 통해 특정 입출력스트림str의 ios 형식 플래그를 지정 가능합니다.- cppreference : fixed
#include <iostream>
void print(const char* textNum, double num)
{
std::cout << "The number " << textNum << " in fixed : " << std::fixed << num << '\n';
std::cout << "The number " << textNum << " in scientific: " << std::scientific << num << '\n';
std::cout << "The number " << textNum << " in hexfloat : " << std::hexfloat << num << '\n';
std::cout << "The number " << textNum << " in default : " << std::defaultfloat << num << "\n\n";
}
int main()
{
print("0.01 ", 0.01);
print("0.00001", 0.00001);
}The number 0.01 in fixed : 0.010000
The number 0.01 in scientific: 1.000000e-02
The number 0.01 in hexfloat : 0x1.47ae14p-7
The number 0.01 in default : 0.01
The number 0.00001 in fixed : 0.000010
The number 0.00001 in scientific: 1.000000e-05
The number 0.00001 in hexfloat : 0x1.4f8b59p-17
The number 0.00001 in default : 1e-05#include <iostream>
#include <sstream>
int main()
{
double f;
std::istringstream("0x1P-1022") >> std::hexfloat >> f;
std::cout << "Parsing 0x1P-1022 as hex : " << f << '\n';
}Parsing 0x1P-1022 as hex : 2.22507e-308width[top]
- setw 및 특정 입출력스트림에 대한
str.width(n);은 다음 입출력 명령에서 활용될 문자열 길이를 지정합니다. - c4learn
- cppreference : setw
#include <iostream>
#include <iomanip>
int main()
{
std::cout << "no setw:" << 42 << '\n';
std::cout << "setw(6):" << std::setw(6) << 42 << '\n';
std::cout << "hello" << std::setw(6) << "world" << std::setw(3) << "!!" << '\n';
}no setw:42
setw(6): 42
hello world !!hello world !!을 출력하는 예시에서 hello 다음에 오는 setw(6)를 봅시다. 다음에 수행될 입출력 명령(여기서는 'world'출력) 에서 범위를 6으로 지정합니다. world는 5글자이기 때문에, 6칸에 해당하는 범위 중 5칸은 world로 채우고 남은 한 칸은 공백으로 남깁니다. 이후의 !! 을 출력할때도 마찬가지입니다.
#include <iostream>
#include <iomanip>
#include <sstream>
int main()
{
std::istringstream is("hello, world");
char arr[10];
is >> std::setw(6) >> arr;
std::cout << "Input : " << is.str() << '\n';
std::cout << "Parsed with setw(6) : " << arr << '\n';
}Input : hello, world
Parsed with setw(6) : hellofill[top]
setw()등으로 출력문(입력은 관계 없음)에 주어지는 공간의 공백 구간을 채우는 문자를 지정합니다.str.setfill(charT c)을 통해 특정 입출력스트림str에 대해 적용 가능합니다.- cppreference : setfill
#include <iostream>
#include <iomanip>
int main()
{
std::cout << "default fill : " << std::setw(10) << 42 << '\n';
std::cout << "setfill('*') : " << std::setfill('*') << std::setw(10) << 42 << '\n';
char prev = std::cout.fill('x');
std::cout << "Replaced '" << prev << "' with '"
<< std::cout.fill() << "': " << std::setw(10) << 42 << '\n';
}default fill : 42
setfill('*') : ********42
Replaced '*' with 'x': xxxxxxxx42left, right, internal[top]
- 출력시(입력은 관계 없음) 문자열 정렬 방식을 지정합니다.
left,right는 모든 출력 형식에 대해서 좌측/우측 정렬 형식을 지정합니다.internal의 경우 정수형, 부동소수점, 화폐 형식을 출력할 때 prefix를 좌측에, 값을 우측에 정렬합니다.str.setf(std::ios_base::left, std::ios_base::adjustfield),str.setf(std::ios_base::right, std::ios_base::adjustfield),str.setf(std::ios_base::internal, std::ios_base::adjustfield)을 통해 특정 입출력스트림str의 ios 형식 플래그를 지정 가능합니다.- cppreference : left
#include <iostream>
#include <iomanip>
int main()
{
std::cout.imbue(std::locale("en_US.utf8"));
std::cout.setf(std::ios_base::hex, std::ios_base::basefield);
std::cout.fill('*');
std::cout << "Left fill:\n" << std::left
<< std::setw(12) << -1.23 << '\n'
<< std::setw(12) << std::showbase << 42 << '\n'
<< std::setw(12) << std::put_money(123, true) << "\n\n";
std::cout << "Internal fill:\n" << std::internal
<< std::setw(12) << -1.23 << '\n'
<< std::setw(12) << 1.23 << '\n'
<< std::setw(12) << 42 << '\n'
<< std::setw(12) << std::put_money(123, true) << "\n\n";
std::cout << "Right fill:\n" << std::right
<< std::setw(12) << -1.23 << '\n'
<< std::setw(12) << 42 << '\n'
<< std::setw(12) << std::put_money(123, true) << '\n';
}Left fill:
-1.23*******
0x2a********
USD1.23*****
Internal fill:
-*******1.23
********1.23
0x********2a
USD*****1.23
Right fill:
*******-1.23
********0x2a
*****USD1.23