cspdiuxX%
로 구현한다.It will manage any combination of the following flags: ’-0.*’ and minimum field width with all conversions
이건 뭔소리지 ?-0.*
4개의 문자로 번역해라.- , 0
은 flags를 의미한다. (밑에서 정리)*
은 정수를 입력받아서 처리하는 문자이다..
은 정밀도를 나타내기위한 기호이다. nfge
도 번역길이
도 번역'#' ' ' '+'
도 번역...
을 붙여 매개변수의 개수가 정해지지 않았다는 표시를 해준다. (...
뒤에는 다른 매개변수를 지정할 수 없다.) 반환값 자료형 함수이름(자료형 고정매개변수, ...)
{
...
}
va_list
타입에 저장된 인수들에 접근하기 위해서는 stdarg
에 정의된 매크로를 사용한다.void va_start(va_list ap, last);
va_list
의 인수턴스와 마지막 위치의 고정인수
를 전달한다.args2
에 해당한다....
의 첫번 째 위치를 가르키게 만든다. (고로, 마지막 위치의 고정인수를 넘겨줘야 시작위치를 구분할 수 있다.) void va_test(const char *str, ...) {
va_list ap;
printf("input str is : [%s]\n", str);
va_start(ap, str);
printf("ap address : [%p]\n", ap);
}
int main(int argc, const char *argv[]) {
va_test("TEST");
va_test("TOAST", 1, 2);
}
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);
void printfNumbers(int args, int args2, ...)
{
va_list ap;
va_start(ap, args2);
for (int i = 0; i < args; i++){
int num = va_arg(ap, int);
printf("%d ", num);
}
va_end(ap);
printf("\n");
}
형식 문자열(format)
에 지정되어 있는 형태로 출력한다.형식 태그(format tag)
라 불리는 것이 추가적으로 들어갈 수 있는데, 이에 대응하는 인자를 형식 태그가 지정한 형태로 치환되어 출력된다.%[플래그(flag)][폭(width)][.정밀도(precision)][길이(length)]서식 문자(specifier)
서식 문자 | 설명 | 예시 |
---|---|---|
c | 문자 | 'a' |
d, i | 부호 있는 10진 정수 | |
u | 부호 없는 10진 정수 | |
e | 지수 표기법으로 출력, e문자 사용 | 3.9265e + 2 |
E | 지수 표기법으로 출력, E문자 사용 | 3.9265E + 2 |
f | 십진법 부동 소수점 수 | |
g | %f와 %e중에서 짧은 것을 사용 (소문자) | |
G | %F와 %E중에서 짧은 것을 사용 (대문자) | |
o | 부호 없는 8진수 정수 | |
s | 문자열 | |
x | 부호 없는 16진 정수(소문자) | 1000(16) => 3e8 |
X | 부호 없는 16진 정수(대문자) | 1000(16) => 3E8 |
p | 포인터 주소 | |
n | 아무것도 출력하지 않는다. but 부호 있는 int형 포인터를 함께전달해야 한다. 전달 된 포인터에 출력 된 문자열의 갯수가 저장된다. | int num 1; printf("123%n6789\n", &num1); // 123456789 printf("num : %d\n", num1); // 3 printf("12345%n6789\n", &num1); // 123456789 printf("num : %d\n", num1); // 5 printf("1%n6789\n", &num1); // 16789 printf("num : %d\n", num1); // 1 |
% | %를 출력한다 | printf("%%\n"); // % |
width
에서 *
로 인자를 음수로 받은 경우 -
부호는 flag
로 인식된다.0
은 #, -, ' '
와 함께 쓰일 수 있다.-
와 0
이 함께 쓰이면, 0
은 무시된다. // +, ' '가 같이 쓰이면 '+'가 우선시 된다.
printf("[% 010d]\n", 123); //[ 000000123]
printf("[%+ 010d]\n", 123); //[+000000123]
printf("[% +010d]\n", 123); //[+000000123]
기호 | 설명 |
---|---|
- | 왼쪽 정렬하여 출력한다. |
+ | 양수(+), 음수(-)의 부호를 출력한다. |
' ' (space) | 양수는 '+' 부호를 붙이지않고 공백으(' ')로 표시, 음수는 '-'로 표시. |
# | 진법에 맞게 숫자 앞에 표시한다. 0, 0x, 0X |
0 | 출력 대상 width 의 빈 공간을 0으로 채운다. |
정수 값
으로 입력받는다.*
로 입력된 경우는 반드시 인자로 정수를 함께 입력받아야하며, 입력값이 width로 설정된다.*
의 인자로 음수가 들어오는 경우 부호 -
는 flag로 처리된다. int width = 10;
printf("flag[*], width[%d] => [%*d]\n",width, width, 12345); // [ 12345]
앞에 마침표(.)
를 찍어야 한다. (폭과 구분하기위하여).
마침표 뒤에 정수입력을 하지 않는 경우도 존재한다. (링크4 참조)0
을 출력한다고 했을 때, 정수%.d
와 실수%.f
의 결과는 다르다.*
로 입력되는 경우 인자로 정수를 함께 입력받고, 입력값이 precision으로 설정된다.*
의 인자로 음수가 들어오는 경우 정밀도는 0
으로 처리된다. // 123
printf("%10.3s\n","12345");
// -00123
printf("%10.5d\n", -123);
// -123
printf("% 10.1d\n", -123);
// 123.1235
printf("%10.4f\n", 123.123456789);
int zeroI = 0;
float zeroF = 0;
// zeroI : [], zeroF : [0]
printf("zeroI : [%.d], zeroF : [%.f]\n", zeroI, zeroF);
출력할 데이터의 자료형 범위를 설정한다.
%d
서식문자의 경우 정수형 데이터를 10진법으로 출력
의 의미를 가진다. 여기에 길이를 지정해주면 출력할 데이터 자료형의 크기를 지정할 수 있다.
길이 | d, i | o, u, x, X | f F e g G a A | c | s | p | n |
---|---|---|---|---|---|---|---|
default | int | unsigned int | float, double | int | char * | void * | int * |
hh | signed char | unsigned char | signed char * | ||||
h | short int | unsigned short int | short int * | ||||
l | long int | unsigned long int | double | wint_t | wchar_t * | long int * | |
ll | long long int | unsigned long long int | long long int * | ||||
j | intmax_t | uintmax_t | intmax_t * | ||||
z | size_t | size_t | size_t * | ||||
t | ptrdiff_t | ptrdiff_t | ptrdiff_t * | ||||
L | long double |
.(점)
을 기준으로 정수
와 실수
를 구분한다.정수
와 실수
를 구분할 수 있어야 한다.정수
부는 10진수 변환과정과 동일하게 2로 나눈 나머지를 몫이 0이될 때까지 구한다.실수
는 실수부(소수점 아래)
가 0이될 때까지 계속해서 2를 곱한다.정수부
(0 or 1)를 처음부터 차례대로 나열하면 된다.(정수는 마지막 부터 읽는다면, 실수는 처음부터 읽는다.)정수부
=> 1100
실수부
0.125
x 2 => 0
.250.25
x 2 => 0
.50.5
x 2 => 1
.0001
으로 표현.1100.001
정수
와 실수
를 표현하는 비트수를 정해놓고 해석한다.1bit = 부호
, 16bit = 정수
, 15bit는 실수
를 표현한다고 가정
한다면12.125
는 2진수로 1100.001
이기 때문에 실수
에 해당하는 2진수 100
은 15비트 공간에 저장 된다. (뒷자리는 0으로 채움)정수
의 범위가 적고, 실수를 표현할 때 정밀도
또한 떨어지게 된다.실수
를 2진수로 표현할 때 자리수가 계속해서 늘어나게 된다.0.34
x 2 => 0
.680.68
x 2 => 1
.360.36
x 2 => 0
.720.72
x 2 => 1
.440.44
x 2 => 1
.88실수 부
를 최대 15bit
로 표현하게 된다. 따라서 고정 소수점방식의 실수는 정밀도
가 낮다. (부동소수점 방식에 비해)고정소수점
과 반대로 소수점을 나타내는 "점"의 위치가 바뀐다는 특징을 가진다. (고정적이지 않다.)1bit는 부호비트
이다.가수부
를 나타내는 비트.가수부
에 저장한다.8bit
배정도는 11bit
로 표현한다.지수부
를 나타내는 비트.2^n
위치부터 실수임을 구분할 수 있다.n + 1
비트부터는 실수(소수점 이하)
를 나타낸다.정밀도
를 높이고 정수의 표현 범위도 넓힐 수 있다.2진수로 변환된 실수
를 정해진비트에 저장하는 것이아니라, 정규화 과정
을 통해 실수 및 정수의 표현범위를 넓힐 수 있다.12.125
의 2진수 1100.001
을 1.100001
* 2^n
으로 나타내도록 하는것이다.정수부가 1만 남을때까지(중요)
소수점을 이동시킨다. (왼쪽 or 오른쪽) 그리고 이동한 칸 수만큼 n 자리
에 집어 넣으면 된다.100001
에서 2^3
이동한 후부터의 bit는 실수
를 표현함을 구분할 수 있다.n
의 크기에 따라 계속 변한다.부동 소수점방식
이라 표현한다.1.100001 * 2^n
과 같은 표기법을 과학적 표기법
이라고 한다.지수부
에 값을 저장할 때는, bias값이라는 걸 더해주는데 4byte에선 127이된다.-127 ~ +128
의 값을 가질 수 있고, 0~126은 음수
127은0
128~255은 양수
를 표현한다. (8byte에서 bias값은 1023) (+1)
x 2^(130 - 127)
x (1 + 2^-1 + 2^-6)
1bit = 부호
, 8bit = n
, 23bit는 이진수
를 표현한다고 한다면?23bit
공간에 이진수를 표현할 수 있다.1.xxx ...
와 같은 형태이다.100001 ...
이 채워진다.1
을 숨겨진 비트(hidden bit)
라고 한다. 실수 표현의 시작 bit는 1
이 생략되있음을 절대로 망각하지 말자.8bit
공간에는 실수 자료형이 표현된 비트를 구분할 수 있는 2^n
의 값을 저장할 수 있다. 의문점 1
, 그렇다면 n비트 이후 부터 실수다 !를 구분할 수 있다면 n이 가수부의 23bit를 넘어가면 어떻게 될까?정수
로 해석한다. 또한 초과되는 bit만큼 0을 채워넣음으로써, 큰 범위의 정수를 표현한다.1(hidden bit) 000 0000 0000 0000 0000 0001
일 때 지수부의 n이 30이라고 한다면?1(hidden bit) 000 0000 0000 0000 0000 0001
0000 00
과 같이 6bit가 0으로 채워짐으로써, 가수부에서 나타내는 정수가 더 큰 값을 가지고 있다는 것을 의미하게 된다. [ 00 00 20 41 ]
이다.[0100] [0001] [0010] [0000]
[0000][0000][0000][0000]이 된다.0
, 지수비트 = 10000010
, 가수비트는 010 0000 0000 ...
이 된다.(-1)^0
x 2^(130 - 127)
x (1 + 2^-2)
로 해석할 수 있다.1 x 2^3
x 1 + 0.125
= 8 x 1.125 = 10.0
이 된다. 10.0f
가 메모리에 [00 00 20 41]
과 같이 저장되어있을 때 리틀 엔디안 방식에 따라 해석하기위해 마지막 byte인 41
부터 해석한다.char *
로 변환.시작주소 + 3byte이동
으로 찾을 수 있다.0000 0001
) 과 비트연산 &
를 수행한다.0100 0001
이므로 (이해가 안된다면 참조 비트단위 연산 보기) 가장앞의 0
100 0001부터 1과 비교하기위해 쉬프트 연산
을 수행한다. (char *로 변환 된 시작주소 + 3) >> 7
하면 0100 0001
이 0000 0000
이 되니깐 메모리의 0번째 bit를 맨 오른쪽으로 옮긴 후, 이 값이 1인지 0인지 알 수 있다. float d = 10.0f;
unsigned char* ptr;
ptr = (unsigned char*)&d;
unsigned char dif = 128;
int j = 0;
for (int i = sizeof(float) - 1; i >= 0; i--) {
for (j = 7; j >= 0; j--)
{
// 8765 4321 이렇게 있으면 8을 1로보내서 1하고 & 연산 함.
printf("%d", (*(ptr + i) >> j) & 0x01);
}
printf(" ");
}
typedef struct s_flag
{
char plus;
char minus;
char space;
char hash;
char zero;
} t_flag;
typedef struct s_input
{
char *str;
char sign;
int len;
} t_input;
typedef struct s_printf
{
va_list *ap;
t_input *input;
t_flag *flags;
char *length;
char specifier;
int width;
int precision_len;
} t_printf;
%
이후에 나오는 printf의 옵션들을 저장.char *str
에 저장, 부호 및 저장 된 str 크기를 기록flag
는 0개이상 존재할 수 있다. printf("%%010d :[%010d]\n", 12345); //[0000012345]
// ↓ warning: '0' flag ignored with precision and '%d' gnu_printf format occured
printf("%%010.1d :[%010.1d]\n", 12345); // [ 12345]
The unsigned int argument is converted to unsigned octal (o), unsigned decimal (u), or unsigned hexadecimal (x and X) notation.
0~ffffffff
범위이다.ffffffff
은 unsigned int 의 max값이다. => 4294967295
printf("%x", 0)
=> 0
printf("%x", -1)
=> ffffffff
printf("%x", -2)
=> fffffffe
printf("%x", -3)
=> fffffffd
printf("%x", UINT_MAX)
=> ffffffff
UINT_MAX + n + 1 (음수일 때)
과 같다.정수부
는 n/10 >= 1
반복해서 구해서 double로 저장한다.123.00000000
이런식으로실수부(소수점 이하)
는 n - 위에서 구한 정수
로 처리한다.123.456700 - 123.000000
이런식으로..정밀도 + 1
크기만큼 문자열로 만든다.libftprintf.a
가 ar되어서 그냥 libft파일도 다 명시함.printf
소스가 있는 root에 clone해서, make re하면 됨.n, f, 길이
추가로 검사.(g, e는 구현 안함)