학습 목표
! 본 내용은 검토 전 포스트 입니다. 부정확한 내용이 있을 수 있으니 양해바랍니다.
- printf 함수 사용 방법을 학습한다.
- 값을 출력하는 방법을 학습한다.
1. 출력
문자열 출력하는 방법은 문자열을 출력해주는 기능인 printf에 문자열을 넣어주면 된다. 앞으로 ~해주는 기능을 함수(Function)라고 하겠다. 함수명() 안에 넣어주는 값들을 인자(Argument)라고 한다. printf 함수의 풀네임은 print format으로 서식(foramt)에 맞게 출력해주겠다는 뜻이다. printf 함수에 인자들은 출력할 서식과 값들로 되어있다.
printf("서식문자", 값);
printf("서식문자1 서식문자2 서식문자3", 값1, 값2, 값3);
2. 서식 문자
서식을 맞춰야 할 경우에 서식 문자라는 것을 사용하게 되는데 서식 문자 - 쌍으로 1대 1 대응하여 작성한다. 앞서 설명했다시피 서식 문자는 특정 형식에 맞게 값을 저장 혹은 출력 할 수 있게 해준다. 문자열은 문자열 전용 서식 문자를 사용하고, 정수는 정수 전용 서식 문자를 사용한다. 하지만 목적에 따라 문자를 정수 서식 문자를 사용해 출력, 입력 하는 등 혼용해서 사용할 수 있다.
2.1. 서식 문자의 종류
부호 있는 10진수 정수 | int | %d |
---|---|---|
부호 없는 10진수 정수 | unsigned int | %u |
부호 없는 16진수 정수 | unsigned int | %x |
실수 | float | %f |
double | %lf | |
문자 | char | %c |
문자열 | char * | %s |
포인터의 주소 | void * | %p |
3. 문자열 출력
문자열을 출력을 해보겠다. 큰 따옴표로 문자열을 감싸고 이를 printf 함수로 감싸주면 된다. 문자열 하나 출력하기 위해서는 서식을 사용하지 않아도 된다.
#include <stdio.h>
int main(void) {
printf("Hello world!"); // Hello world!
return 0;
}
서식에 맞게 문자열을 출력해 줄 수 있다. 아래 코드는 서식문자를 통해 “Hello world!”를 출력하는 코드이다.
#include <stdio.h>
int main(void) {
printf("%s", "Hello world!"); // Hello world!
return 0;
}
3.1. 제어 문자
역슬래쉬 + n으로 이루어진 \n은 개행(줄바꿈) 기능을 한다. 이처럼 문자이지만 특별한 역할을 하는 문자를 제어 문자라고 한다.
#include <stdio.h>
int main(void) {
printf("Hello\nworld!"); // Hello
world!
return 0;
}
자주쓰는 문자는 아래와 같다. 제어문자는 아니지만 나머지(%)를 출력하기 위해서 %% 를 사용한다.
줄바꿈 | \n |
---|---|
탭 | \t |
작은 따옴표(’) | \’ |
큰따옴표(”) | \” |
역슬래쉬() | \ |
daehun : “hi” 라는 문자열을 출력하고자 한다. 이때 작은따옴표는 일반적으로 사용할 수 없으므로 개행문자와 함께 작성해야 한다.
#include <stdio.h>
int main(void) {
printf("daehun : \"hi\""); // 잘못된 예시
return 0;
}
|
4. 변수 출력
아래 코드는 변수 age에 20담아 20을 출력하는 코드이다. 나머지 알지 못하는 코드들이 작성되어있지만 지금은 이해하지 않아도 된다.
#include <stdio.h>
int main(void) {
int age = 20;
printf("%d\n", age); // 20
return 0;
}
변수에 값을 넣지 않고 출력하면 알 수 없는 값이 출력되었다. 이를 쓰레기 값(Garbage value)로 부른다. 아무의미 없어보이는 이 값들은해커는 특정 상황에서 쓰레기 값을 분석하고 해킹에 사용한다.
#include <stdio.h>
int main(void) {
int age;
printf("%d\n", age); // -858993460
return 0;
}
4.1. 여러 변수 출력
여러 변수를 출력하기 위해서는 자료형에 맞는 서식 문자를 작성 후 순서대로 넣으면 된다.
#include <stdio.h>
int main(void) {
int num1 = 1, num2 = 2;
printf("%d %d", num1, num2); // 1 2
return 0;
}
매개변수를 부족하게 두었을 경우 warning 메세지와 함께 앞에 하나만 출력되게 된다. 반대로 서식문자는 2개지만 변수를 하나만 넣을 때는 num1의 값과 쓰레기값이 뜨게 된다.
#include <stdio.h>
int main(void) {
int num1 = 1, num2 = 2;
printf("%d", num1, num2); // 1
return 0;
}
#include <stdio.h>
int main(void) {
int num1/ = 1;
printf("%d %d", num1); // 1 52124560
return 0;
}
5. 정수-실수 서식문자 혼용
int는 정수이기 때문에 서식문자로 %d를 사용해야하지만 실수의 서식문자인 %lf를 사용하면 어떻게 될까? 아래와 같이 전혀 다른 내용이 뜨게 된다.
#include <stdio.h>
int main(void) {
int num = 1;
printf("%lf", num); // 0.000000
return 0;
}
반대로 %lf를 사용해야하는 실수에 서식문자인 %d를 사용해보았다. 이역시 쓰레기 값이 나왔다.
#include <stdio.h>
int main(void) {
double num = 1.23;
printf("%d", num); // 2061584302
return 0;
}
5.1. 강제 형변환(Type casting)
코드를 짜다보면 부득이하게 서식문자 %d에 실수를 출력해야할 일이있다. 이때 강제 형변환을 시켜주면 된다. 이는 printf 함수의 변수 앞에 (자료형)을 입력하면된다. 실수를 정수로 형변환하면 소숫점 제외 정수만 남고 정수를 실수로 형변환하면 소숫점이 생기게 된다.
#include <stdio.h>
int main(void) {
double num = 1.23;
printf("%d", (int)num); // 2061584302
return 0;
}
#include <stdio.h>
int main(void) {
double num = 1;
printf("%lf", (double)num); // 1.000000
return 0;
}
6. 정수-문자 서식문자 혼용
이번에는 문자를 정수의 서식문자인 %d로 출력하고자한다. 49라는 꽤 의미있어보이는 정수가 나왔다. 이는 아스키 코드 규칙을 통해 생성된 정수이다.
#include <stdio.h>
int main(void) {
char ch = '1';
printf("%d", ch); // 49
return 0;
}
6.1. 아스키코드(ASCII code)
ASCII (American Standard Code for Information Interchange)는 미국 정보 교환 표준 부호이다. 컴퓨터에서 사용하는 특수문자, 알파벳 등을 사전에 숫자쌍으로 약속해 놓은 것이다. 48번 ~ 57번은 숫자, 65번 ~ 90번은 대문자, 97번 ~ 122번은 소문자이다.
소문자 a는 대문자 A의 숫자에서 +32한 만큼이므로 아래와 같이도 출력할 수 있다.
#include <stdio.h>
int main(void) {
printf("%c", 'A'+32); // a
return 0;
}
아래는 자주쓰이는 특수문자이다. 아스키코드 번호로 외워두는 것을 추천한다.
NULL은 이후에 서술하겠다.
NULL | 0 |
---|---|
공백 | 32 |
줄바꿈 | 20 |
6.2. 해킹에서의 아스키코드
웹해킹을 할때 admin이라는 단어를 출력해야하는데, admin 단어가 정책에 의해 막혀있다면 이때 아스키코드를 사용할 수 있다. chr은 정수를 아스키코드로 바꿔주는 역할을 하는데 chr(97) + chr(100) + chr(109) + chr(108) + chr(110)로 a + d + m + i + n 문자를 합쳐 admin 단어를 완성시킬 수 있다.
진법을 변환해서도 사용할 수 있는데 admin의 아스키코드를 다른 진법으로 변경하여. 16진수 0x61646D696E, 2진수 0110000101100100011011010110100101101110등으로 바꿔서 사용할 수 있다.
7. 서식문자 응용
서식문자의 다양한 옵션으로 문자열을 더욱 유연하게 사용할 수 있다.
7.1. 소숫점 출력
실수를 출력할때 원하는 소숫점 아래 갯수만큼 출력하고 싶다면 서식문자 %lf가운데 .소숫점 갯수를 입력하면 된다.
#include <stdio.h>
int main(void) {
double num = 1;
printf("%lf", num); // 1.000000
printf("%.3lf", num); // 1.000
return 0;
}
7.2. 문자열 정렬
문자열을 출력할때 일정 규정에 맞게 작성해야하는 경우가 있다. 띄어쓰기로도 공백을 지정할 수 있지만 이는 너무 번거롭다.
#include <stdio.h>
int main(void) {
printf("이름 나이 소속\n");
printf("김대훈 25 Pay1oad\n");
printf("이동하 20 Zeropointer\n");
return 0;
}
서식문자 %s 가운데 정수를 통해 일정 공백을 마련할수 있다. 정수가 양수이면 우측정렬 음수이면 좌측정렬이다.
#include <stdio.h>
int main(void) {
printf("%3s %2s %10s\n", "이름", "나이", "소속");
printf("%3s %2s %10s\n", "김대훈", "25", "Pay1oad");
printf("%3s %2s %10s\n", "이동하", "20", "Zeropointer");
return 0;
}
#include <stdio.h>
int main(void) {
printf("%3s %2s %10s\n", "이름", "나이", "소속");
printf("%3s %2s %-10s\n", "김대훈", "25", "Pay1oad");
printf("%3s %2s %-10s\n", "이동하", "20", "Zeropointer");
return 0;
}
해킹에서 역시 문자열 크기 조정을 사용한다 임의의 이유로 임의 문자(공백 포함) 100개를 넣어야 하는 경우 스페이스바로 100개를 넣는것보다는 개행문자 %100s를 사용한다.
#include <stdio.h>
int main(void) {
printf("%100s", "");
return 0;
}
8. 순서에 맞게 인자 넣기
기본적으로 출력을 위해서는 자료형에 맞게 순서대로 하나씩 작성하면 된다. 특수한 경우 순서를 바꿔 출력해야하는 경우가 있다. 아래와 같이 작성할 수 있다. 해킹시
%[순번]$[자료형]
%2$d
아래 코드를 보면 %2$d에는 두번째 인자가, %1$d에는 첫번재 인자가 들어가는 것을 알 수 있다.
#include <stdio.h>
int main(void) {
printf("%2$d %1$d", 1, 2); // 2, 1
return 0;
}
9. Format String Bug
FSB(Format String Bug)는 서식문자(Format string)과 관련된 취약점이다. 아래 코드는 str 문자열을 사용자로 부터 입력 받고 문자열을 출력하는 코드이다. 문자열을 출력하기 위해 보통 오른쪽과 같은 코드를 작성하지만 더욱 간추려 왼쪽과 같은 코드를 작성 할 수 있다.
|
|
printf(str)과 같이 서식문자를 작성하지 않고 입력을 통해 서식문자를 지정할 수 있으면 메모리값을 읽을 수 있을 뿐 만 아니라 원하는 변수에 값을 넣을수 도 있다.
#include <stdio.h>
int main(void) {
char str[256];
scanf("%s", str); // 입력 : AAAA %p %p %p %p
printf("%s"); // 출력 : (원래 읽을 수 없는 값)
}
'초보 해커를 위한 C언어와 동작 원리 > Ch2. Programming' 카테고리의 다른 글
조건문 (0) | 2025.04.22 |
---|---|
연산자 (0) | 2025.04.22 |
주석 (0) | 2025.04.22 |
변수&상수 (0) | 2025.01.27 |
환경 구축 (0) | 2025.01.27 |