프로젝트/42Seoul
42서울 본과정 - Ft_printf
soohykim
2025. 4. 11. 10:16
728x90
반응형
📒 Technical consideration
when
- 23.04.08 토 12:00 ~ 15:30
- 23.04.16 일 16:00 ~ 22:00
- 23.04.19 수 16:00 ~ 01:00
- 23.04.22 토 17:00 ~ 22:30 (평가)
내용
프로그램 이름 | libftprintf.a |
제출 파일 | .c, .h, Makefile |
Makefile | NAME, all, clean, fclean, re |
외부 함수 | malloc, free, write, va_start, va_arg, va_copy, va_end |
libft | 사용 가능 |
📌 주의사항
- norm error 금지
- segmetation fault, bus error, double free 금지
- heap에 동적 할당된 메모리 해제 (메모리 누수 방지)
- Makefile
- -Wall -Wextra -Werror 플래그 지정
- relink 금지 (다시 make했을 때 재실행 금지)
- $(NAME), all, clean, fclean, re 규칙 포함
- 전역 변수 사용 금지
- 본 기능을 구현하기 위한 sub function 정의 시 static으로 정의
→ 정의되지 않은 참조 막기 위해
- 본 기능을 구현하기 위한 sub function 정의 시 static으로 정의
- libft 사용
- 소스와 Makefile을 libft 폴더에 복사해야함
- 프로젝트 Makefile은 libft의 Makefile을 사용하여 라이브러리를 컴파일한 다음, 프로젝트 컴파일 해야함
- library를 만들기 위해서 ar command 사용
- libtool 사용 금지
📒 Mandatory part
📕 printf 정의
1) header file
- #include <stdio.h>
2) function prototype
- int ft_printf (const char*, ...)
3) description
- 서식화된 출력 지원 (c, s, p, d, i, u, x, X, % 구현)
- 일반 문자열 : 출력 스트림에 그대로 전달되어 출력 (실제 printf처럼 버퍼 관리 수행x)
- % + 형식 태그 : 추가 인자를 받아 출력 스트림에 어떻게 출력해야 할지 가이드 제공
- 형식 태그 : %와 서식 지정자로 구성되어 서식 지정자에 따라 다양한 해석 방식 나타냄
4) 서식 지정자 구현
- %c : single character 출력
- Character
- %s : string (문자열) 출력 (str() 내장 함수 사용)
- String of Charcters
- %p : void* 형식의 포인터 인자를 16진수로 출력
- %d : 10진수 정수 출력 (10진수)
- Signed Decimal Integer
- %i : 10진수 정수 출력 (8/10/16진수)
- Signed Decimal Integer
- %u : 부호 없는 10진수 숫자 출력
- Unsinged Decimal Integer
- %x : 소문자를 사용하여 숫자를 16진수로 출력
- Unsinged Hexadecimal Integer
- %X : 대문자를 사용하여 숫자를 16진수로 출력
- Unsinged Hexadecimal Integer
- %% : 퍼센트 기호 (%) 출력
5) return value
- 인쇄된 문자 수 반환 (문자열 출력을 종료하는 데 사용되는 null 바이트 제외)
- 출력하는 항목의 길이 (int형) 반환
📖 참고 📖 conversion specifier(변환 지시어)
- 개념
- = 문자열 포맷 문자, 서식 문자
- %와 conversion 문자(s,d,f) 사이에 전체 자릿수와 소숫점 뒤 자리수 지정 가능
- 종류
- %c : repr() 내장 함수 사용
- %f/F : 부동소수점(floating-point) 실수 출력
- %o/O : 8진수 출력
- %e/E : 부동소수점 실수를 지수 형태로 출력
- %g/G : 부동소수점을 일반 실수 형식이나 지수 형식으로 변환해 출력 (즉, 값에 따라 %e 혹은 %f로 변환)
📕 가변 인자
1) 개념
- #include <stdarg.h>
- 정의 : 함수에 인자의 개수가 다르게 할당되어도 처리
- 특징
- 최소 1개 이상의 고정 인자 필요 (0개 이상의 가변 인자)
- 선택 인자를 먼저 받으면 함수의 원형에서 어느 인자를 고정 인자로 받은 지 알 수 없기 때문
- 가변인자 (...)는 파라미터 순서 상 가장 뒤에 위치
2) 가변 매크로
va_list
- 정의 : 가변 인자 목록
- 특징
- 가변변수를 가리킬 ap 포인터 선언
- typedef를 통해 내부적으로 char *로 정의
va_start(ap, str)
- 인자
- ap : 가변인자(va_list) 변수
- str : 고정인자
- 가변 인자를 가져올 수 있도록 가변 인자 시작 주소 참조하는 포인터 설정
- ap가 str 개수만큼 가리킴
- 마지막 필수 인자를 매개 변수로 넣기만 하면 자동으로 가변 인자의 시작 주소를 계산하여 ap에 할당해주는 역할
#define va_start(ap, v) ((ap) = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v))
- ap : va_list로 만든 포인터
- v : 마지막 고정인수
- _ADDRESSOF(v) : &(v), 즉 주소로 바꿔주는 매크로
- _INTSIZEOF(n) : ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1)), 마지막 고정인수의 사이즈를 구해서 그 다음 인자의 시작주소
(가변인자의 시작주소까지의 메모리상의 거리를 구해주는 매크로)
va_arg(va_list, 자료형)
- 가변 인자를 참조하는 포인터를 통해 역참조 후, 해당 데이터의 크기만큼 민 후 다음 인자를 참조
- 사이즈만큼 가변인자를 가져오는 함수
- va_list가 가리키는 값을 자료형의 크기만큼 리턴 후, 그만큼 뒤로 옮김
- va_list가 참조하고 있는 특정 가변 인자를 역참조하고, va_list내의 다음 가변 인자를 참조하도록 해주는 매크로
#define va_arg(ap, t) (*(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))
- ap : va_list로 만든 포인터
- t : int/long/double 등 타입 이름
- [참고] char/short의 경우 int로 쓰고 형 변환, float의 경우 double로 쓰고 형 변환 (ex. char ch = (char)va_arg(ap, int);)
- 가변 인자를 역참조한 후 가변 인자를 가리키도록 만드는 연산 : 대입 연산자를 통해 특정 타입의 크기 만큼 먼저 밀어서 다음 가변 인자를 가리키도록 만들어 놓은 후 다시 그 특정 타입의 크기만큼을 빼서 현재 참조하고 가변 인자를 역참조하도록 만듦
- _INTSIZEOF(t)만큼 더해놓고 _INTSIZEOF(t)만큼 다시 뺀 값을 t *타입의 포인터 변수를 역참조함
va_end
- 가변 인자를 모두 처리 후, 가변인자를 가리키는 포인터를 NULL로 초기화
- 가변 인자 목록을 지칭하는 va_list 타입의 포인터 변수를 NULL을 할당하면서 가변 인자 사용의 끝낼 때 사용
#define va_end(ap) (ap = (va_list)0)
- ap : va_list로 만든 포인터
- 매크로는 실제로 없어도 프로그램에 지장 없음
- 인텔 계열의 CPU에서는 va_end가 아무 일도 하지 않음
- 다른 플랫폼과의 호환성에서 중요한 역할을 할 수 있으므로 관례적으로 넣어
va_copy
- 가변 인자 목록을 복사
📕 바이트 패딩(Byte Padding)
1) 정의
- 클래스(구조체)에 바이트를 추가해 CPU 접근에 부하를 덜어주는 기법
- 각자의 타입으로 형 변환 하여 값을 읽어내는 것이다.
--> char ch = (char)va_arg(ap, int);
2) 특징
- 메모리에 특정 값이 쓰일 때는 주소 체계 단위로 기록하기 때문
- 8바이트보다 작은 값을 사용할 때에도 패딩을 추가하여 8바이트 단위로 접근하여 한 번 연산에 하나의 값에 접근가능
- 이미 사용이 끝난 va_list를 사용하여도 참조하는 것이 없도록 안전성에 기여
- 장점 : 성능 향상
- 단점 : 메모리가 낭비
📕 write 함수
1) 개념
- count 바이트만큼 파일 디스크립터(fd)가 참조하는 파일의 현재 위치에 시작 지점이 buf인 내용을 기록 (fd가 표현하는 객체에 탐색하는 기능이 없으면, 쓰기 작업은 파일의 처음 위치에서 시작)
- 반환값
- 성공시 : 쓰기에 성공한 바이트 수 (ssize_t) 반환
- 에러시 : -1 반환
2) 에러나는 경우
- O_NONBLOCK : fd가 논블록 모드로 열린 상태에서 쓰기 작업이 블록될 경우
- EBADF : fd가 유효하지 않거나 쓰기 모드가 아닐 경우
- EFAULT : buf의 포인터가 호출하는 프로세스 주소 공간 안에 있지 않을 겅우
- EFBIG : 쓰기 작업이 프로세스 단위로 걸려 있는 최대 파일 제약이나 내부 구현 제약보다 더 큰 파일을 만들 경우
- EINVAL : fd가 쓰기에 적합하지 않은 객체에 매핑되어 있을 경우
- EIO : 저수준 입출력 에러
- ENOSPC : fd가 들어있는 파일시스템에 공간 부족
- EPIPE : fd가 파이프와 소켓에 연결되어 있지만, 반대쪽 단이 닫힌 경우 (프로세스는 SIGPIPE 시그널을 받음)
📕 구현
1) 구조
(1) Str 인자를 받기 (while문 이용)
- % 나오기 전까지 문자 출력
- 출력할 때마다 반환값 길이를 하나씩 증가
(2) %문자 만나는 경우
- 서식 지정자에 해당하는 문자면 변환 / 아니면 변환 무시
(3) 서식 지정자마다 변환하면서 write 함수로 출력
- write함수 오류날 경우 에러 처리
(4) 출력한 string 길이만큼 반환 값 구하기
2) 구현할 함수
(1) 인자 받는 함수 --> ft_argument
(2) 서식지정자에 맞게 변환하는 함수 --> ft_printf_cspdiuxX%
(3) 반환값 길이 구하는 함수 --> 구현x
3) 재귀 구현
- len(출력하는 길이 반환 목적)을 포인터로 사용
📌 ft_printf_c
- write 오류 처리
- len +1 증가
int ft_printf_c(char c, int *len)
{
if (write(1, &c, 1) == -1)
return (-1);
*len += 1;
return (0);
}
📌 ft_printf_s
- write 오류 처리
- len +1 증가
int ft_printf_s(char *s, int *len)
{
size_t i;
i = 0;
if (!s)
{
if (write(1, "(null)", 6) == -1)
return (-1);
*len += 6;
return (6);
}
while (*(s + i))
{
if (ft_printf_c(*(s + i), len) == -1)
return (-1);
i++;
}
return (0);
}
📌 ft_printf_p
- 주소는 16진수로 표현
- 16씩 나머지 값을 인덱스로 16진수 변환 후 배열에 저장
- 저장된 배열을 뒤에서부터 출력 (len +1 증가)
- write 오류 대비 반환값을 변수에 담아 체크
int ft_printf_p(unsigned long long p, int *len)
{
int temp;
temp = 0;
if (p >= 16)
{
temp = ft_printf_p(p / 16, len);
if (temp == -1)
return (-1);
ft_printf_p(p % 16, len);
}
else
{
if (ft_printf_c("0123456789abcdef"[p % 16], len) == -1)
return (-1);
}
return (0);
}
📌 ft_printf_di
- 음수일 경우 '-' 출력 후 -1 곱함
- n이 10보다 클 경우 n / 10, n % 10 재귀
- n이 10보다 작을 경우 문자로 변환 후 출력
- write 오류 대비 반환값을 변수에 담아 체크
int ft_printf_di(long long n, int *len)
{
int temp;
temp = 0;
if (n < 0)
{
if (ft_printf_c('-', len) == -1)
return (-1);
n *= -1;
}
if (n >= 10)
{
temp = ft_printf_di(n / 10, len);
if (temp == -1)
return (-1);
ft_printf_di(n % 10, len);
}
else
{
if (ft_printf_c((n % 10) + 48, len) == -1)
return (-1);
}
return (0);
}
📌 ft_printf_u
- 양수인 부분 d와 구현 동일
- write 오류 대비 반환값을 변수에 담아 체크
int ft_printf_u(unsigned int n, int *len)
{
int temp;
temp = 0;
if (n >= 10)
{
temp = ft_printf_u(n / 10, len);
if (temp == -1)
return (-1);
ft_printf_u(n % 10, len);
}
else
{
if (ft_printf_c((n % 10) + 48, len) == -1)
return (-1);
}
return (0);
}
📌 ft_printf_xX
- 16씩 나머지 값을 인덱스로 16진수 변환 후 배열에 저장
- write 오류 대비 반환값을 변수에 담아 체크
int ft_printf_x(unsigned int n, const char str, int *len)
{
int temp;
temp = 0;
if (n >= 16)
{
temp = ft_printf_x(n / 16, str, len);
if (temp == -1)
return (-1);
ft_printf_x(n % 16, str, len);
}
else
{
if (str == 'x')
{
if (ft_printf_c("0123456789abcdef"[n % 16], len) == -1)
return (-1);
}
else if (str == 'X')
{
if (ft_printf_c("0123456789ABCDEF"[n % 16], len) == -1)
return (-1);
}
}
return (0);
}
📌 ft_argument
- 반환값으로 error 유무 판별
- %p의 경우 재귀 돌리기 위해, 초기 주소 출력값 "0x" 출력
- len 포인터 이용하여 길이 측정
int ft_argument(va_list *ap, const char str, int *len)
{
int error;
error = 0;
if (str == 'c')
error = ft_printf_c((char)va_arg(*ap, int), len);
else if (str == 's')
error = ft_printf_s(va_arg(*ap, char *), len);
else if (str == 'p')
{
if (write(1, "0x", 2) == -1)
return (-1);
*len += 2;
error = ft_printf_p(va_arg(*ap, unsigned long long), len);
}
else if (str == 'd' || str == 'i')
error = ft_printf_di(va_arg(*ap, int), len);
else if (str == 'u')
error = ft_printf_u(va_arg(*ap, unsigned int), len);
else if (str == 'x')
error = ft_printf_x(va_arg(*ap, unsigned int), len);
else if (str == 'X')
error = ft_printf_lx(va_arg(*ap, unsigned int), len);
else if (str == '%')
error = ft_printf_c('%', len);
return (error);
}
📌 ft_printf
- % 만날 경우 서식지정자에 맞는 함수 호출
- % 만나지 않을 경우 출력
int ft_printf(const char *str, ...)
{
int len;
va_list ap;
len = 0;
va_start(ap, str);
while (*str)
{
if (*str == '%')
{
str++;
if (ft_argument(&ap, *str++, &len) == -1)
return (-1);
}
else
{
if (ft_printf_c(*str++, &len) == -1)
return (-1);
}
}
va_end(ap);
return (len);
}
4) 반복문 구현
- len(출력하는 길이 반환 목적)을 함수 반환값으로 줌
📌 ft_printf_c
- write 오류 처리
- len 반환
int ft_printf_c(char c)
{
int len;
len = 0;
if (write(1, &c, 1) == -1)
return (-1);
len += 1;
return (len);
}
📌 ft_printf_s
- write 오류 처리
- len 반환
int ft_printf_s(char *s)
{
int i;
int len;
i = 0;
len = 0;
if (!s)
{
if (write(1, "(null)", 6) == -1)
return (-1);
len += 6;
return (6);
}
while (*(s + i))
{
if (ft_printf_c(*(s + i)) == -1)
return (-1);
i++;
len++;
}
return (len);
}
📌 ft_printf_p
- 초기 주소 출력값 "0x" 출력
- 16씩 나머지 값을 인덱스로 16진수 변환 후 배열에 저장
- 저장된 배열을 뒤에서부터 출력 후 len 반환
int ft_printf_p(unsigned long long p)
{
int i;
int len;
char c[16];
i = 0;
len = 0;
if (ft_printf_s("0x") == -1)
return (-1);
while (p >= 16)
{
c[i] = "0123456789abcdef"[p % 16];
p /= 16;
i++;
}
c[i] = "0123456789abcdef"[p];
len = ft_printarr(c, i, len);
if (len == -1)
return (-1);
return (len + 2);
}
📌 ft_printf_di
- 음수일 경우 '-' 출력 후 -1 곱함
- n이 10보다 클 경우 나머지를 문자로 변환후 배열에 저장
- 저장된 배열을 뒤에서부터 출력 후 len 반환
int ft_printf_di(long long n)
{
int i;
int len;
char c[10];
i = 0;
len = 0;
if (n < 0)
{
if (ft_printf_c('-') == -1)
return (-1);
n *= -1;
len++;
}
while (n >= 10)
{
c[i] = (n % 10) + 48;
n /= 10;
i++;
}
c[i] = (n % 10) + 48;
len = ft_printarr(c, i, len);
if (len == -1)
return (-1);
return (len);
}
📌 ft_printf_u
- 양수인 부분 d와 구현 동일
- n이 10보다 클 경우 나머지를 문자로 변환후 배열에 저장
- 저장된 배열을 뒤에서부터 출력 후 len 반환
int ft_printf_u(unsigned int n)
{
int i;
int len;
char c[10];
i = 0;
len = 0;
while (n >= 10)
{
c[i] = (n % 10) + 48;
n /= 10;
i++;
}
c[i] = (n % 10) + 48;
len = ft_printarr(c, i, len);
if (len == -1)
return (-1);
return (len);
}
📌 ft_printf_xX
- 16씩 나머지 값을 인덱스로 16진수 변환 후 배열에 저장
- 저장된 배열을 뒤에서부터 출력 후 len 반환
int ft_printf_x(unsigned int n)
{
int i;
int len;
char c[10];
i = 0;
len = 0;
while (n >= 16)
{
c[i] = "0123456789abcdef"[n % 16];
n /= 16;
i++;
}
c[i] = "0123456789abcdef"[n];
len = ft_printarr(c, i, len);
if (len == -1)
return (-1);
return (len);
}
📌 ft_argument
- 반환값으로 출력하는 길이 반환
int ft_argument(va_list *ap, const char str)
{
int len;
len = 0;
if (str == 'c')
len = ft_printf_c((char)va_arg(*ap, int));
else if (str == 's')
len = ft_printf_s(va_arg(*ap, char *));
else if (str == 'p')
len = ft_printf_p(va_arg(*ap, unsigned long long));
else if (str == 'd' || str == 'i')
len = ft_printf_di(va_arg(*ap, int));
else if (str == 'u')
len = ft_printf_u(va_arg(*ap, unsigned int));
else if (str == 'x')
len = ft_printf_x(va_arg(*ap, unsigned int));
else if (str == 'X')
len = ft_printf_lx(va_arg(*ap, unsigned int));
else if (str == '%')
len = ft_printf_c('%');
return (len);
}
📌 ft_printf
- % 만날 경우 서식지정자에 맞는 함수 호출
- % 만나지 않을 경우 출력
int ft_printf(const char *str, ...)
{
int len;
int total;
va_list ap;
total = 0;
va_start(ap, str);
while (*str)
{
len = 1;
if (*str == '%')
{
str++;
len = ft_argument(&ap, *str++);
if (len == -1)
return (-1);
}
else
{
if (ft_printf_c(*str++) == -1)
return (-1);
}
total += len;
}
va_end(ap);
return (total);
}
📌 ft_printarr
int ft_printarr(char *c, int i, int len)
{
while (i >= 0)
{
if (ft_printf_c(c[i]) == -1)
return (-1);
i--;
len++;
}
return (len);
}
📌 ft_printf.h
#ifndef FT_PRINTF_H
# define FT_PRINTF_H
# include <unistd.h>
# include <stdlib.h>
# include <stdarg.h>
int ft_argument(va_list *ap, const char str);
int ft_printf(const char *str, ...);
int ft_printf_c(char c);
int ft_printf_s(char *s);
int ft_printf_p(unsigned long long p);
int ft_printf_di(long long n);
int ft_printf_u(unsigned int n);
int ft_printf_x(unsigned int n);
int ft_printf_lx(unsigned int n);
int ft_printarr(char *c, int i, int len);
#endif
📌 MAkefile
NAME = libftprintf.a
SRCS = ft_printf.c ft_printf2.c
OBJS = $(SRCS:.c=.o)
all : $(NAME)
$(NAME) : $(OBJS)
%.o:%.c ft_printf.h
cc -Wall -Wextra -Werror -c $< -o $@
ar rc $(NAME) $@
clean :
rm -rf $(OBJS)
fclean : clean
rm -rf $(NAME)
re :
make fclean
make all
.PHONY : all clean fclean re
5) main 함수
#include <stdio.h>
int main(void)
{
char c;
char *s;
char *ns;
void *p;
void *np;
int d;
int i;
unsigned int u;
int x;
c = 'a';
s = "abcde";
ns = 0;
p = &d;
np = 0;
d = -2147483648;
i = 2147483647;
u = 4294967295;
x = 10;
ft_printf("<ft_printf>\nc = %c\ns = %s\n s가 NULL일 경우 = %s\n", c, s, ns);
ft_printf("p = %p\n p가 NULL일 경우 = %p\n", p, np);
ft_printf("d = %d\n i = %i\n u = %u\n", d, i, u);
ft_printf("x = %x\n X = %X\n %% = %%\n", x, x);
printf("----------------------------------------------------------------\n");
printf("<printf>\nc = %c\ns = %s\n s가 NULL일 경우 = %s\n", c, s, ns);
printf("p = %p\n p가 NULL일 경우 = %p \n", p, np);
printf("d = %d\n i = %i\n u = %u\n", d, i, u);
printf("x = %x\n X = %X\n %% = %%\n", x, x);
}
- 실행 결과
📌 d옵션과 i옵션 차이
- 공통점 : Singed Decimal Integer (부호 있는 10진 정수)
- 차이점 : 출력은 동일하지만 입력에 차이가 있음
- d옵션 : 부호 있는 10진 정수로 입력 받음
- i옵션 : 부호 있는 8진/10진/16진 정수로 입력 받음
📌 %기호 출력
형식 문자열을 이용할 때는 % 기호를 이용하여 형식 태그의 시작임을 알리게 된다. % 기호를 출력하기 위해선 \로는 출력할 수 없고 오로지 % 기호를 이용해서만 출력할수 있다.
단순히 printf를 이용하여 기호를 출력하려 하면 아래와 같이 경고 문구를 띄우면서 컴파일이 되지 않는 것을 볼 수 있다.
특수 문자들을 출력하는 Escape Sequence()를 이용하여 출력하려 해도, 경고 문구를 띄우면서 컴파일을 막는 모습을 확인할 수 있다.
📒 Bonus part
📕 플래그
문자 % 다음 0개 이상의 플래그가 올 수 있음
1) #
- 값은 "대체 형식"으로 변환
- o 변환 의 경우 : 출력 문자열의 첫 번째 문자는 0이 됩니다(아직 0이 아닌 경우 0을 접두사로 사용)
- x 및 X 변환 의 경우 : 0이 아닌 결과 앞에 문자열 "0x"(또는 X 변환의 경우 "0X")가 추가
- a , A , e , E , f , F , g 및 G 변환 의 경우 : 결과 뒤에 숫자가 없더라도 결과에 항상 소수점이 포함
2) 0
- 값을 0으로 채우기
- d , i , o , u , x , X , a , A , e , E , f , F , g 및 G 변환의 경우 변환된 값의 왼쪽은 공백이 아닌 0으로 채워짐
- 0 및 - 플래그가 모두 나타나면 0 플래그 는 무시
- 숫자 변환( d , i , o , u ,x , X ), 0 플래그는 무시
3) -
- 변환된 값은 필드 경계에서 왼쪽으로 조정됨 (기본값은 오른쪽 맞춤)
- n번의 변환을 제외하고 변환된 값은 왼쪽이 공백/0이 아니라 오른쪽이 공백으로 채워짐
- A - 둘 다 주어지면 0 을 무시합니다 .
4) ' '
- (공백) 부호 있는 변환으로 생성된 양수(또는 빈 문자열) 앞에는 공백이 있음
5) +
- 부호(+ 또는 -)는 항상 부호 있는 변환에 의해 생성된 숫자 앞에 위치
- A +는 둘 다 사용되는 경우 공백을 재정의
📕 필드 폭
- 최소 필드 너비를 지정하는 선택적 10진수 문자열(0이 아닌 첫 번째 숫자 포함)
- 변환된 값의 문자 수가 필드 너비보다 적으면 왼쪽(또는 왼쪽 조정 플래그가 지정된 경우 오른쪽)에 공백이 채워짐
- 10진수 문자열 대신 "" 또는 "m$"(일부 10진수 m 의 경우)를 작성하여 필드 너비가 각각 다음 인수 또는 m 번째 인수에 지정함
- int 유형
- 음수 필드 너비는 양수 필드 너비가 뒤따르는 '-' 플래그로 간주함
- 어떤 경우에도 존재하지 않거나 작은 필드 너비로 인해 필드가 잘리지 않음
- 변환 결과가 필드 너비보다 넓으면 변환 결과를 포함하도록 필드가 확장됨
📕 정밀도
- 마침표('.') 뒤에 선택적 10진수 문자열이 오는 형식의 선택적 정밀도
- 10진수 문자열 대신 "" 또는 "m$"(일부 10진 정수 m의 경우)를 작성하여 정밀도가 각각 다음 인수 또는 m번째 인수에 제공되도록 지정
- int 유형의 . 정밀도가 '.'로만 제공되거나 정밀도가 음수이면 정밀도는 0으로 간주
- d, i, o, u, x 및 X 변환에 대해 표시되는 최소 자릿수 a, A, e에 대한 기수 문자 뒤에 표시되는 자릿수를 제공
- E, f 및 F, g, G 변환의 최대 유효 자릿수 또는 s, S 변환 의 경우 문자열에서 인쇄할 최대 문자 수
728x90
반응형