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이므로 (이해가 안된다면 참조 비트단위 연산 보기) 가장앞의 0100 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값이다. => 4294967295printf("%x", 0) => 0printf("%x", -1) => ffffffffprintf("%x", -2) => fffffffeprintf("%x", -3) => fffffffdprintf("%x", UINT_MAX) => ffffffffUINT_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는 구현 안함)