Skip to content

Instantly share code, notes, and snippets.

@wlsvy
Last active August 12, 2020 16:24
Show Gist options
  • Save wlsvy/329df8104a9b51bd65f6cda0dc2acde4 to your computer and use it in GitHub Desktop.
Save wlsvy/329df8104a9b51bd65f6cda0dc2acde4 to your computer and use it in GitHub Desktop.
C++ IOS API에서 유용하다 싶은 부분을 주관적으로 작성한 문서입니다.

C++ IOS API에서 유용하다 싶은 부분을 주관적으로 작성한 문서입니다.

차례

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이 더 빠르다고 합니다.

Reference

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, 0

precision[top]

#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.23456789012

showpoint[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.14159

showpos[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.1342

showbase[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: 52

uppercase[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-10

dec, 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 : 2

fixed, 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-308

width[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) : hello

fill[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': xxxxxxxx42

left, 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment