[ft_printf] 과제 정리, Mandatory part

최별 Choi Byeol·2022년 5월 25일
0

42Seoul

목록 보기
5/6

printf 함수 구현하기

가변 인자

  • 상황에 따라 함수 인자의 개수가 다르더라도 처리할 수 있게 해주는 것
  • 헤더: stdarg.h
  • int ft_printf(const char *str, ...) 와 같이 최소 1개 이상의 고정된 인수가 있어야 하며, ...은 파라미터 순서상 맨 마지막에

타입과 매크로 함수

  • 타입
    • va_list: 가변 인자의 주소를 저장하기 위한 포인터 자료형(char *)
  • 매크로 함수
    • va_start: va_list 타입의 포인터를 첫 번째 가변 인자 주소로 초기화하는 함수
      • va_start(ap, v)
    • va_arg: va_list 타입의 포인터를 다음 인자 값으로 이동시키고, 현재 인자 값을 가져오는 함수
      • 가변 인자 메모리공간에서, 전달한 자료형의 크기만큼 값을 가져온다.
      • 값을 가져온 후, 포인터의 주소를 자료형 크기만큼 뒤로 옮겨서 다음 값을 가져올 수 있도록 한다.
    • va_end: va_list 타입의 포인터를 NULL로 초기화하는 함수. 가변 인자의 사용을 종료할 때 사용(free 함수와 비슷한 역할)
      • va_end 매크로 함수 없이 사용을 종료해도 별 지장은 없지만 다른 플랫폼에서의 호환성과 안정성을 위해 사용하는 것이 좋다.
    • va_copy: 가변 인자 리스트를 복사하는 함수
    • https://jhnyang.tistory.com/293

+ 알고 있으면 편리한 명령어들

라이브러리 사용해서 컴파일

cc main.c -L./ -lftprintf

터미널 명령어

  • 새로운 터미널: cmd + t
  • 터미널 쪼개기: cmd + d
  • 터미널 닫기: cmd + w

vim 명령어

  • 편집: edit 파일이름
  • 비교: vs 파일이름
  • 수평 쪼개기: sp 파일 이름
  • 여러 개 켜놓고 왔다갔다: ctrl + w 하고 화살표
  • 끄고 싶은 터미널에서 q

Mandatory part

서식 지정자

  • %c: 단일 문자 출력
  • %s: 문자열 출력
  • %p: void * 형식의 포인터 인자를 16진수로 출력(포인터의 메모리 주소)
  • %d: 10진 정수 출력
  • %i: 10진 정수 출력
    • %d, %i의 경우 printf에서는 차이가 없고, scanf인 경우 %d는 signed 10진 정수만, %i는 10진수/8진수/16진수를 입력 받을 수 있다.
  • %u: 부호 없는(unsigned) 10진 정수 출력
  • %x: 소문자를 사용해 숫자를 부호 없는(unsigned) 16진수로 출력
  • %X: 대문자를 사용해 숫자를 부호 없는(unsigned) 16진수로 출력
  • %%: % 출력

ft_printf.h

#ifndef FT_PRINTF_H
# define FT_PRINTF_H

# include <stdarg.h>
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>

int	ft_printf(const char *str, ...);
int	ft_putchar(char c);
int	ft_putstr(char *str);
int	ft_itoa(int i);
int	ft_uitoa(int n);
int	ft_puthex(int i, char x);
int	ft_putpointer(unsigned long long l);

#endif

ft_printf.c

#include "ft_printf.h"

int	callspecifier(char c, va_list args)
{
	unsigned long long	p;

	if (c == 'c')
		return (ft_putchar((char)va_arg(args, int)));
	else if (c == 's')
		return (ft_putstr(va_arg(args, char *)));
	else if (c == 'x' || c == 'X')
		return (ft_puthex(va_arg(args, int), c));
	else if (c == '%')
		return (ft_putchar('%'));
	else if (c == 'd' || c == 'i')
		return (ft_itoa(va_arg(args, int)));
	else if (c == 'u')
		return (ft_uitoa(va_arg(args, int)));
	else if (c == 'p')
	{
		p = va_arg(args, unsigned long long);
		if (p == 0)
			return (ft_putstr("0x0"));
		else
			return (ft_putstr("0x") + ft_putpointer(p));
	}
	return (0);
}

int	ft_printf(const char *str, ...)
{
	va_list	args;
	int		i;
	int		sum;

	if (!str)
		return (0);
	va_start(args, str);
	i = 0;
	sum = 0;
	while (str[i])
	{
		if (str[i] == '%')
		{
			i++;
			if (!str[i])
				break ;
			sum += callspecifier(str[i], args);
		}
		else
			sum += ft_putchar(str[i]);
		i++;
	}
	va_end(args);
	return (sum);
}

ft_putchar.c

#include "ft_printf.h"

int	ft_putchar(char c)
{
	write(1, &c, 1);
	return (1);
}

ft_putstr.c

#include "ft_printf.h"

int	ft_putstr(char *str)
{
	int	i;

	i = 0;
	if (!str)
		str = "(null)";
	while (str[i])
	{
		ft_putchar(str[i]);
		i++;
	}
	return (i);
}

ft_itoa.c

#include "ft_printf.h"

static long	countdigit(long n)
{
	int	i;

	i = 1;
	while (n > 9)
	{
		n = n / 10;
		i++;
	}
	return (i);
}

static void	putnbr(long n)
{
	if (n > 9)
		putnbr(n / 10);
	ft_putchar(n % 10 + '0');
}

int	ft_itoa(int n)
{
	long	l;
	int		size;

	size = 0;
	l = n;
	if (l < 0)
	{
		ft_putchar('-');
		l *= -1;
		size += 1;
	}
	size += countdigit(l);
	putnbr(l);
	return (size);
}

int	ft_uitoa(int n)
{
	unsigned int	u;
	int				size;

	size = 0;
	u = (unsigned int)n;
	size += countdigit(u);
	putnbr(u);
	return (size);
}

ft_puthex.c

#include "ft_printf.h"

int	charcount(unsigned long long nb)
{
	int	i;

	i = 1;
	while (nb >= 16)
	{
		nb = nb / 16;
		i++;
	}
	return (i);
}

void	putnbr_base(unsigned long long nb, char *base)
{
	if (nb >= 16)
		putnbr_base((nb / 16), base);
	ft_putchar(base[nb % 16]);
}

int	ft_puthex(int i, char x)
{
	char			*base;
	int				sum;
	unsigned int	c;

	base = "0123456789abcdef";
	if (x == 'X')
		base = "0123456789ABCDEF";
	sum = 0;
	c = (unsigned int)i;
	putnbr_base(c, base);
	sum += charcount(c);
	return (sum);
}

int	ft_putpointer(unsigned long long l)
{
	char	*base;
	int		sum;

	base = "0123456789abcdef";
	sum = 0;
	putnbr_base(l, base);
	sum += charcount(l);
	return (sum);
}

Makefile

NAME = libftprintf.a
cc = gcc
CFLAGS = -Wall -Wextra -Werror

SRCS = \
	  ft_printf.c \
	  ft_putchar.c \
	  ft_putstr.c \
	  ft_itoa.c \
	  ft_puthex.c

OBJS = $(SRCS:.c=.o)

all: $(NAME)

$(NAME): $(OBJS)

%.o: %.c
	$(CC) $(CFLAGS) -c -o $@ $^
	ar crsu $(NAME) $@

clean:
	rm -f $(OBJS)

fclean: clean
	rm -f $(NAME)

re: clean all

.PHONY: all clean fclean re

main.c (테스트용)

#include "ft_printf.h"

int	main(void)
{
	printf("%c \n", 'a');
	printf("%s \n", "abc");
	printf("%p \n", (void *)42);
	printf("%d %i \n", 42, 42);
	printf("%u \n", 42);
	printf("%x %X \n", 42, 42);
	printf("%% \n\n");

	ft_printf("%c \n", 'a');
	ft_printf("%s \n", "abc");
	ft_printf("%p \n", (void *)42);
	ft_printf("%d %i \n", 42, 42);
	ft_printf("%u \n", 42);
	ft_printf("%x %X \n", 42, 42);
	ft_printf("%% \n");
	return 0;
}

cc -Wall -Wextra -Werror ft_printf.c ft_putchar.c ft_putstr.c ft_itoa.c ft_puthex.c main.c

profile
FE 👩🏻‍💻

0개의 댓글