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
전역 변수 사용 금지
libft 사용
library를 만들기 위해서 ar command 사용
📖 참고 📖 conversion specifier(변환 지시어)
- 개념
- = 문자열 포맷 문자, 서식 문자
- %와 conversion 문자(s,d,f) 사이에 전체 자릿수와 소숫점 뒤 자리수 지정 가능
- 종류
- %c : repr() 내장 함수 사용
- %f/F : 부동소수점(floating-point) 실수 출력
- %o/O : 8진수 출력
- %e/E : 부동소수점 실수를 지수 형태로 출력
- %g/G : 부동소수점을 일반 실수 형식이나 지수 형식으로 변환해 출력 (즉, 값에 따라 %e 혹은 %f로 변환)
필수 인자
를 매개 변수로 넣기만 하면 자동으로 가변 인자
의 시작 주소를 계산하여 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_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 *타입의 포인터 변수를 역참조함
#define va_end(ap) (ap = (va_list)0)
- ap : va_list로 만든 포인터
- 매크로는 실제로 없어도 프로그램에 지장 없음
- 인텔 계열의 CPU에서는 va_end가 아무 일도 하지 않음
- 다른 플랫폼과의 호환성에서 중요한 역할을 할 수 있으므로 관례적으로 넣어
(1) Str 인자를 받기 (while문 이용)
(2) %문자 만나는 경우
(3) 서식 지정자마다 변환하면서 write 함수로 출력
(4) 출력한 string 길이만큼 반환 값 구하기
(1) 인자 받는 함수 --> ft_argument
(2) 서식지정자에 맞게 변환하는 함수 --> ft_printf_cspdiuxX%
(3) 반환값 길이 구하는 함수 --> 구현x
int ft_printf_c(char c, int *len)
{
if (write(1, &c, 1) == -1)
return (-1);
*len += 1;
return (0);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
int ft_printf_c(char c)
{
int len;
len = 0;
if (write(1, &c, 1) == -1)
return (-1);
len += 1;
return (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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
#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
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
#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);
}
형식 문자열을 이용할 때는 % 기호를 이용하여 형식 태그의 시작임을 알리게 된다. %
기호를 출력하기 위해선 \
로는 출력할 수 없고 오로지 %
기호를 이용해서만 출력할수 있다.
단순히 printf를 이용하여 기호를 출력하려 하면 아래와 같이 경고 문구를 띄우면서 컴파일이 되지 않는 것을 볼 수 있다.
특수 문자들을 출력하는 Escape Sequence()를 이용하여 출력하려 해도, 경고 문구를 띄우면서 컴파일을 막는 모습을 확인할 수 있다.
문자 % 다음 0개 이상의 플래그가 올 수 있음