Ft_PrintF

Yineng Zhang
4 min readJun 10, 2019

Ft_printf is a project at the programming school, 42 Silicon Valley. It is my recreation of the C function printf. I started the project doubting that I could actually do it, and ended up with more confidence in my programming skills when I finished. Through this project I learned about variadic functions, system calls, and different ways to approach algorithmic problems. The hardest parts was figuring out the scope of what printf can do and then trying to match it within the limitations given by 42. Within a month I have managed to pass 2442/2472 of the tests made by Gavin, which are more rigorous than necessary. I could’ve done all of them, but 2442 is a palindrome for 42(lul), however I will upload a version that passes all of them on my Github.

The structure of ft_printf is as follows: the main format parser; the flag/modifier parser; the conversion dispatcher ; and each conversion. The main format parser takes a variable amount of variables using variadic functions. It is prototyped as: int ft_printf(const char *format, …). We first initialize an starting va_list and set it equal to the start of the variable list(go read about variadic functions if this makes no sense to you). This is passed into the main parser which differentiates between things that you want printed out vs conversions starting with %. Once it finds a % sign, the flag/modifier parsing goes through and saves them into a data struct which is taken by the conversion function and passed into each conversion to be processed into an output.

The main format parser works by indexing through the format and printing out the characters if it isn’t a % sign. If it is a % sign it looks forward and compares it to the string ALLSYMBOLS, which is a macro of all possible conversions, flags, and modifiers (defined in the header file: cspdiouxXfy%#-+ .*0123456789hLljz). If it isn’t then it breaks it means that the input is incorrect and we don’t want to be stuck there. We then look at the next character and go through the loop until we hit ‘\0’. However, if the char matches one of the options in ALLSYMBOLS it goes to the second phase of parsing. If the character is one of “#-+ .*0123456789hLljz”, function parse 2 will just save it as an option in our data struct below, and continue on. It will continue until it hits one of the chars “cspdiouxXfy%” aka one of the conversions.

Before we continue, this is the data struct that holds all modifiers. It is passed into the next portion as an recipe. Filling in this menu is done in the format parse function. It is filled in and then passed into the conversion portion of the parse2 function (see below, highlighted portion).

The conversion is simple it simply based on what character format[pos] is it dispatches it into the appropriate conversion formula (see below).

Each of the functions is passed the struct f (aka menu) from 2 pictures above, and based on what the original printf does it mimics. For example, what happens if there is a precision ‘.’ and no number after? Or, what happens if there is a zero flag and width/precision? You will have to experiment with the original printf and read some documentary. I don’t have enough space to fully explain each. Check this out for some general ideas: http://www.cplusplus.com/reference/cstdio/printf/. It is also helpful to use Gfielder’s pft test on GitHub to handle the edge cases.

Each conversion function depends on how the user wants to organize it. I originally made each as one function, however since it was getting to be hundreds of lines long apiece, so I developed an method to keep it readable. I divided it into 4 parts: length of object, width, and precision. For example if you wanted to do printf(“%5.3d”, 42). It is asking us to print an int with an width of 5, and precision of 2. We take the pointer s and turn it into a string with itoa_base(s, 10). The length is found using ft_strlen(s) or 2. The precision would be 3–(length)2 = 1, and the width would be 5–(length)2–(precision)1 = 2. According to this I would print 2 blanks, 1 zero, and the characters “4” and “2”.

Do this for each of the conversions you want to do and you will be done!! Some improvements I could make are to introduce a buffer, and use bitwise for my modifiers. It would greatly improve the speed. See ya!

--

--