Search code examples
cprototypeunsigned

Is it unsafe to pass an unsigned long to a function which uses a long?


Foreword: I am not allowed to use any functions from the C library

I have this function:

char *to_base(long nbr, char *base)
{
    static char buffer[50];
    char    *ptr;
    int     base_len;

    ptr = &buffer[49];
    *ptr = 0;
    base_len = ft_strlen(base);
    while (nbr != 0)
    {
        *--ptr = base[nbr % base_len];
        nbr /= base_len;
    }
    return (ptr);
}

As we can see it takes a long. In my program I have an unsigned long which I have to translate into its hexadecimal value. Is it unsafe to pass the unsigned long at this function ? If yes how can I make it work ?

EDIT : Here is how I am currently using it:

unsigned long    val;
char            *hexa;

val = (unsigned long)va_arg(*list, void *);
hexa = to_base(val, "0123456789abcdef");

Solution

  • Is it unsafe to pass the unsigned long at this function ?

    It's "safe", as in the program will not format your hard drive or start another world war.

    Passed function arguments are converted to the argument type. The unsigned value will be converted to a signed one. All architectures today use twos-complement, it's easy to predict the result. Your compiler should document the behavior, ex. in gcc implementation defined beahvior:

    The result of, or the signal raised by, converting an integer to a signed integer type when the value cannot be represented in an object of that type (C90 6.2.1.2, C99 and C11 6.3.1.3).

    For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised.

    "reduced modulo 2^N" - basically 2^N is subtracted until the value is within range. So if you have 32-bit longs and have (long)(unsigned long)4294967196ul so you subtract 2^32 from the value and it's equal to (long)-100.

    If yes how can I make it work ?

    Properly handle negative numbers.

    And write a separate function for unsigned and signed numbers.

    Also (unsigned long)va_arg(*list, void *); is casting a void* pointer value to an unsigned long (?). Most probably you want va_arg(list, unsigned long) - to take unsigned long from arguments.