-9

I am recoding the printf function. The problem is with limits, I cannot print ULONG_MAX number for instance.

printf("%lu", ULONG_MAX) gives me ->18446744073709551615

ft_putnbr(ULONG_MAX) gives me -> -1

I included the two following libraries :

<limits.h> 
<locale.h>

And put in my main():

setlocale(LC_ALL, ""); 

My putnbr is a basic recursive function like this (works well with other numbers):

void    ft_putnbr(int nb)
{
    if (nb < 0)
    {
        ft_putchar('-');
        nb = -nb;
    }
    if (nb >= 10)
    {
        ft_putnbr(nb / 10);
        ft_putnbr(nb % 10);
    }
    else
    {
        ft_putchar(nb + '0');
    }
}

Any help would be very appreciated.

ziKmouT
  • 175
  • 2
  • 2
  • 13
  • 2
    Show the definition of `ft_myprintf()` as well – CinCout Jan 13 '16 at 06:56
  • Add it to your question. And add ft_nb_arg, ft_print_it, and whatever else you are calling. Do you think people can read your mind? – gnasher729 Jan 13 '16 at 07:02
  • Here is my code available: https://bitbucket.org/zikmout/ft_printf – ziKmouT Jan 13 '16 at 07:03
  • 2
    Your `ft_putnbr()` function takes an `int` parameter. How can that hold ULONG_MAX? – Marc Khadpe Jan 13 '16 at 07:04
  • Ok I change it and try right now but I don't think it is going to make it work out... – ziKmouT Jan 13 '16 at 07:06
  • what does it mean by "Does not work"? what does it output? – phuclv Jan 13 '16 at 07:14
  • First off, you need to declare the argument to `ft_putnbr` as `unsigned long`. Declaring it as `int` is doubly wrong: (1) wrong size (2) signed instead of unsigned. Once you've fixed that, look at the very first thing you do: You see if it's less than `0`. An unsigned can never be less than 0, so when properly declared, that test will always fail. It's dead code. Try making some fixes and posting the corrected code. – Tom Karzes Jan 13 '16 at 07:16
  • and how does an unsigned type have negative value? – phuclv Jan 13 '16 at 07:17
  • I want to make it print the right number but now with it does now print the correct number with negative number – ziKmouT Jan 13 '16 at 07:20

4 Answers4

1

Well the first thing you do is check to see if nb is less than 0.

This is true in the case of ULONG_MAX (nb is passed as an int, not an unsigned int) so you take the first branch.

"-" is printed and then -1 is turned to 1.

The in the final iteration only the character 1 is printed.

LPs
  • 16,045
  • 8
  • 30
  • 61
ViNi89
  • 114
  • 1
  • 8
0

Since it seems that you have a bug hidden somewhere in code that is too long to show, I suggest that you go back to good old debugging.

Hint: A parameter of type int won't be able to hold every value of type unsigned long.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
0

The bug is that your ft_putnbr() function takes an int parameter. There're two problems with that when you pass it a variable of type unsigned long as in this case. Both can be replicated with this snippet:

#include <limits.h>
#include <stdio.h>

int main() {
    unsigned long my_long = ULONG_MAX;
    int my_int = (int) my_long;
    printf("%lu\n", my_long);
    printf("%i\n", my_int);
}

The first problem is that the parameter is of a type of shorter length than the value you try to pass to the function. Let's assume that long is 2 bytes on our system while int is 1 byte (more realistically they would be 4 or 8 bytes). In binary, ULONG_MAX would then be 1111 1111 1111 1111. However, when assigning that to int, which only is 1 byte, the value will be 1111 1111 as there's only room for 8 bits. In order to pass ULONG_MAX, we need a type of the same (or greater) length so there's room for all bits. For example, we could use long so that the function signature becomes ft_putnbr(long nb);.

There's, however, still one problem. The type long is signed (i.e., one of the bits is dedicated to keep track of whether the number is negative or positive) while ULONG_MAX is of unsigned type (i.e., only positive). In particular, if the first bit is 1, then that indicates that the number is negative. So a signed 2 byte type with binary value 1111 1111 1111 1111 will be negative. The reason that it becomes (decimal) -1 is beyond this answer (but you can read about it here: http://en.wikipedia.org/wiki/Two%27s_complement).

So, how can we solve both of these problems? One approach would be to let ft_putnbr() take a very wide signed type (e.g., long long) and never pass it any unsigned type of equal or greater length. Another approach would be to write two ft_putnbr() (with different names): one that takes the widest signed type and one that takes the widest unsigned type.

Fredrik Savje
  • 565
  • 2
  • 14
0

Ok, thanks to you guys I made it work for both limits (LONG_MAX & LONG_MIN):

void    ft_putnbr(long long int nb)
{
    if (nb == LONG_MIN)
        ft_putstr("-9223372036854775808");
    if (nb < 0 && nb != LONG_MIN)
    {
        ft_putchar('-');
        nb = -nb;
    }
    if (nb >= 10 && nb != LONG_MIN)
    {
        ft_putnbr(nb / 10);
        ft_putnbr(nb % 10);
    }
    else if (nb != LONG_MIN)
    {
        ft_putchar(nb + '0');
    }
}
ziKmouT
  • 175
  • 2
  • 2
  • 13