C++/카루의 C++ 강좌

[카루의 C++ 강좌] 1-4. 출력하기 - std::cout와 std::printf()

카루-R 2020. 3. 21. 00:18
반응형

지난 시간에 다양한 타입과 함께 머리가 터지셨을 겁니다. 아무튼.. 이번에는 이제 std::cout를 통해 다양한 값을 출력해 보도록 하죠!

std::endl

std::cout << "2020년 3월 20일";
std::cout << "나는 잠도 못 자고 포스팅을 하고 있다.";

앞으로 코드가 이렇게 간결하게 나오는 경우, main함수 안에 작성하시면 됩니다.

분명히 저는 std::cout를 두 줄로 나누어 작성했습니다. 하지만 막상 출력해보면? 붙어서 나오죠.

std::endl 은 END of Line으로써 줄을 바꿔주는 역할을 합니다. (출력 버퍼를 비워주기도 하지만, 이는 나중에 설명하겠습니다.)

std::cout << "2020년 3월 20일" << std::endl;
std::cout << "나는 잠도 못 자고 포스팅을 하고 있다.";

이제 의도한 대로 줄이 띄어집니다. 그리고, 한 번 std::cout을 쓰면 << 연산자는 계속 이어지기 때문에 위 두 문장을 하나로 합칠 수도 있습니다.

std::cout << "2020년 3월 20일" << std::endl << "나는 잠도 못 자고 포스팅을 하고 있다.";

이렇게요. 그런데, std::endl 대신 문자열 안에서 줄바꿈을 할 수도 있습니다.

문자열과 이스케이프 시퀀스 (제어 문자)

문자열은 여러개의 문자가 모인 것으로, "큰따옴표로 묶어서" 표현합니다. 그 안에 우리가 표현하고 싶은 말을 아무렇게나 쓸 수 있습니다.

auto string = "아 피곤해 아 졸려 아 배고파 아 치킨 아 삼겹ㅅ...";
std::cout << string << std::endl;

이렇게 auto 변수에 저장했다가 출력하는 것도 가능하죠.

(참고로 저때의 타입은 const char* 입니다만.. 이건 '5-2. 포인터 기본'에서 다루겠습니다)

참고로 문자열엔 몇가지 특징이 있습니다.

1. 붙어있는 문자열은 하나의 문자열로 취급됩니다.

auto str = "아 피곤해." "아 배고파";
std::cout << str << std::endl;     // 아 피곤해.아 배고파

2. 문자열을 여러 줄에 걸쳐서 사용하려면 문장의 끝에 \(역슬래쉬)를 붙여줍니다.

하지만, 줄 바꿈도 안 될 뿐더러 들여쓰기를 하면 문자열 자체에 공백이 포함되기 때문에 1번의 방법을 추천합니다.

auto str = "아 피곤해." "아 배고파\
     여러 줄에 걸쳐 사용";    // 이렇게 들여쓰기를 하면 빈 공간이 문자열에 포함이 됩니다.

auto str = "아 피곤해. 아 배고파" // 따옴표로 문자열을 끝냅니다.
    "여러 줄에 걸쳐 사용";    // 이렇게 하면 들여쓰기를 해도 상관이 없습니다.

참고로 백슬래쉬 기호가 우리나라에선 원화 기호로 보입니다. ​\ = \ 같은 기호입니다.

그리고 이스케이프 시퀀스, 즉 제어 문자에 대해 설명하겠습니다.

\n

개행 문자. 다음 줄의 맨 앞으로 이동합니다(줄바꿈)

\r

현재 줄의 맨 앞으로 이동합니다.

\a

비프음 또는 경고음을 냅니다.

\t

탭(Tab) 문자입니다.

\\, \', \"

각각 \, ', " 문자를 표현합니다.

제어 문자는 문자 또는 문자열 안에서만 효력이 발생합니다.

우선 개행 문자를 먼저 보겠습니다.

std::cout << "2020년 3월 20일\n나는 잠도 못 자고 포스팅을 하고 있다.";

문자열 중간에 개행 문자가 들어가 있습니다. 이 부분은 엔터키와 동일한 효과를 냅니다.

2020년 3월 5일
나는 잠도 못 자고 포스팅을 하고 있다.

이렇게 std::endl 대신 \n을 사용하여 줄바꿈을 할 수도 있습니다.

​​

\r은 커서를 맨 앞으로 옮깁니다. 이때, 지우는 역할은 하지 않습니다.

예제 코드를 보시죠.

std::cout << "12HS: Be the Bridge to the Future!\r" << std::endl;

// 출력 결과
12HS: Be the Bridge to the Future!

이렇게만 보면 아무런 역할을 하지 않는 것 처럼 보입니다. \r 뒤에 문자를 좀 더 추가해 보겠습니다.

std::cout << "12HS: Be the Bridge to the Future!\rGG" << std::endl;

// 출력 결과
GGHS: Be the Bridge to the Future!

GG를 분명히 \r 뒤에 작성했는데 앞 글자가 GG로 바뀌었습니다! 네, \r은 커서를 현재 줄의 맨 앞으로 옮기고, 그 뒤에 있는 문자는 이미 출력된 글자 위에 덮어씁니다. 자주 쓰지는 않지만 가끔씩 요긴하게 쓸 곳이 있습니다.

\a는 원래 컴퓨터 내장스피커에서 나는 비프음을 출력합니다. 데스크탑 PC에서 전원 킬 때 "삑!" 소리나는 그거요. 하지만 이상하게 윈도우 10에선 그냥 자체 경고음을 출력합니다.

std::cout << "Alarm!\a" << std::endl;

// 출력 결과
Alarm! // + 경고음 (비프음)

문자열은 ""로 둘러싸이기 때문에 내부에서 "을 그냥 사용할 수 없습니다. \"로 사용해야 하고 마찬가지고 \\, \' 이런 식으로 사용해야 하는 문자들이 있습니다.

std::cout << "backslash: \\" << std::endl;
std::cout << "이것은 \"큰따옴표\"" << std::endl;
std::cout << "그리고 \'작은따옴표'" << std::endl; // 작은따옴표는 \가 없어도 상관없다.

// 출력 결과
backslash: \
이것은 "큰따옴표"
그리고 '작은따옴표'

날 문자열 리터럴(RAW String Literals) (C++11)

나는 순수하게 따옴표와 역슬래쉬를 사용하고 싶은데, 이스케이프 시퀀스가 불편할 때가 있습니다. 특히나 따옴표를 많이 쓴다면 더더욱.

R"구분자( /* 문 자 열 */ )구분자" 

그래서 정말 아무거나 써도 되게 해 주는 '날 문자열 리터럴'이 새로 등장했습니다. R"()" 이렇게 쓰고, 저 괄호 안에 아무 표현이나 쓰면 됩니다. 구분자는 없어도 상관 없습니다.

#include <iostream>

int main()
{
    std::cout << R"(아무거나\막 써도 "상관" 없다? 심지어

엔터도 된다!!)" << std::endl;
}
아무거나\막 써도 "상관" 없다? 심지어

엔터도 된다!!

심지어 엔터도 순수한 문자로 취급합니다. 오히려 저 안에선 \n이 안 먹힙니다. 상황에 따라서 굉장히 유용할 듯 합니다.

자, 이제 본격적으로 변수를 출력해 봅시다!

#include <iostream>

int main()
{
    int age{254};
    double pi{3.1415926};
    bool is_true{false};
    auto string{R"(평화롭고 따스한 "봄날")"};
    char ch{'\a'};

    std::cout << "내 나이는 " << age << "살\n";
    std::cout << "원주율의 값은? " << pi << std::endl;

    std::cout << "C++은 쉬워, 그렇지? " << is_true << std::endl;
    std::cout << string << std::endl;

    std::cout << "경고음아, 울려라!" << ch << std::endl;
    return 0;
}
내 나이는 254살
원주율의 값은? 3.14159
C++은 쉬워, 그렇지? 0
평화롭고 따스한 "봄날"
경고음아, 울려라!

일단 여기서 두 가지 문제가 보입니다.

1) double에 저장한 수 보다 자릿수가 잘려서 출력이 됨

2) bool에는 false라는 값을 저장했는데 0이 출력이 됨

이 부분을 로 해결합니다!

"[C++ 심화] 3. std::cout의 출력 형식 지정"을 참고해 주세요.

물론 이전에 말씀드렸던 대로, 출력문을 한 문장으로 묶을 수 있습니다.

std::cout << "내 나이는 " << age << "살\n"
   << "원주율의 값은? " << pi << std::endl
   << "C++은 쉬워, 그렇지? " << is_true << std::endl
   << string << std::endl
   << "경고음아, 울려라!" << ch << std::endl;

std::printf()

이 함수는 사실 C언어에서 넘어온 함수인데, 서식 문자를 통해 출력을 할 수 있습니다.

printf() 함수의 모습은 이렇습니다.

int printf( const char *_Format [, _Argument] ... ); // <cstdio>에 선언됨

int main() 이랑 비교하면 뭔가 비슷하면서도 다르죠? 바로 사용해 보겠습니다.

함수를 호출할 때는 '함수이름(인자)'의 형식으로 사용합니다. 제가 함수를 설명할 때마다 std::printf이렇게가 아니라 std::printf() 이렇게 설명하는 이유가 여기에 있습니다. 소괄호를 함수 호출 연산자라고 부릅니다.

// std::cout << "2020년 3월 5일" << std::endl;
// std::cout << "나는 잠도 못 자고 포스팅을 하고 있다.";

/* ^^ 대신에 vv */

std::printf("2020년 3월 5일\n");
std::printf("나는 잠도 못 자고 포스팅을 하고 있다.");

참고로 std::printf()에선 std::endl을 쓸 수 없기 때문에 줄 바꿈을 위해선 반드시 이스케이프 문자 \n을 사용해야 합니다.

그리고 변수에 저장된 값을 출력하려면 서식 문자라는 것을 사용해야 합니다.

그리고 변수에 저장된 값을 출력하려면 서식 문자라는 것을 사용해야 합니다.

%c

char

문자

%d, %i

bool, short, int

부호 있는 10진수

%ld, %uld

long, unsigned long

%lld, %ulld

long long, unsigned long long

부호 없는 10진수

%u

unsigned short, unsigned int

%o, %x, %X

int

각각 8진수, 16진수(소문자),

16진수(대문자)

%f

float, double

고정 소수점

%lf, %Lf

double, long double

%e, %E

double

부동 소수점 (지수문자 e, E)

%g, %G

double

고정/부동 소수점 중 간단한 것

%s

문자열

%%

딱히 하는 건 없고 그냥 % 출력

함수에 넘기는 값을 인자라고 하는데, 함수에 인자를 넘길 때는 ',' 로 구분하여 전달합니다.

int n{1};
std::printf("%d", n); // '1'을 출력합니다.

std::printf()에 서식 문자를 사용할 때는 위와 같이 쉼표를 찍고, 출력할 변수를 붙여주면 됩니다.

int x{3}, y{5};
std::printf("%d, %d", x, y);         // 출력결과: 3, 5
std::printf("x = %d, y = %d", x, y); // 출력결과: x = 3, y = 5

서식 문자가 여러개라면 그 뒤에 그 개수만큼 변수를 나열해 주면 됩니다. 서식 문자는 " " 문자열의 어느 곳에 와도 상관이 없고, 서식 문자와 뒤에 오는 인수(=인자)와의 개수가 같아야 합니다. 위는 서식 문자 2개에 인수 2개를 추가로 넘겼습니다.

서식 문자를 연습해봅시다.

int age{254};
double pi{3.1415926};
bool is_true{false};
auto string{R"(평화롭고 따스한 "봄날")"};
char ch{'\a'};

//std::cout << "내 나이는 " << age << "살\n";
//std::cout << "원주율의 값은? " << pi << std::endl;
std::printf("내 나이는 %d살\n", age);
std::printf("원주율의 값은? %lf\n", pi);

// std::cout << "C++은 쉬워, 그렇지? " << is_true << std::endl;
// std::cout << string << std::endl;
std::printf("C++은 쉬워, 그렇지? %d\n", is_true);
std::printf(string); // 문자열을 담은 변수는 바로 출력 가능
std::printf("\n");   // 하지만 \n을 따로 출력해 줘야 함

//std::cout << "경고음아, 울려라!" << ch << std::endl;
std::printf("경고음아, 울려라!%c\n", ch);

다만 C++에서는 std::cout을 더 많이 이용하기 때문에 std::printf()는 몰라도 괜찮습니다.

그리고 나중에 배울, C++20에 추가될 std::format() 을 이용하면 std::printf()를 완전히 대체할 수 있습니다.

1-4. 도전 과제

  1. char 변수에 작은 따옴표를 저장하고, 출력해보세요.
  2. 날 문자열 리터럴을 사용해서 엔터를 출력해 보세요.
  3. std::printf() 함수를 통해 '50%'를 %d를 이용하여 출력해 보세요.

이젠 std::cout가 굉장히 쉬워보이죠? 이제 여러분께선 원하는대로 출력이 가능하실겁니다.

다음 시간에는 std::cin을 통해 입력을 받고, 간단한 계산을 해 보겠습니다.

참고: 본 강좌의 연계 심화 강좌는

"[C++ 심화] 3. std::cout의 출력 형식 지정"입니다.

반응형