0

I wrote a pretty simple function to perform this conversion in C. Is it perfectly safe? if not, what are the other ways?

EDIT: I rewrote the function to add more effective error checks.

#define UNLESS(x) if (!(x))

int char_to_uint(const char *str, unsigned int* res)
{    
    /* return 0 if str is NULL */
    if (!str){
        return 0;
    }

    char *buff_temp;
    long long_str;

    /* we set up errno to 0 before */
    errno = 0;

    long_str = strtol(str, &buff_temp, 10); 

    /* some error and boundaries checks */
    if (buff_temp == str || *buff_temp != '\0' || long_str < 0){
        return 0; 
    }

    /* errno != 0 = an error occured */
    if ((long_str == 0 && errno != 0) || errno == ERANGE){
        return 0;
    }

    /* if UINT_MAX < ULONG_MAX so we check for overflow */
    UNLESS(UINT_MAX == ULONG_MAX){
        if (long_str > UINT_MAX) {
            return 0;
        } else {
            /* 0xFFFFFFFF : real UINT_MAX */
            if(long_str > 0xFFFFFFFF){ 
                return 0;
            } 
        }  
    }

    /* after that, the cast is safe */
    *res = (unsigned int)long_str;

    return 1;
}
  • Returning 0 for an invalid string does not seem useful. If you want to treat `"foo"` as an error, a caller of your function cannot distinguish it from the string`"0"`. For each string, your function returns 0. – William Pursell Jun 23 '22 at 21:37
  • There are plenty of machines where UINT_MAX and ULONG_MAX are the same, so that test of yours for overflow may not do what you want. – Steve Summit Jun 23 '22 at 21:37
  • Ah yes, thanks you. But we must check the value with `UINT_MAX` before casting, no ? – Etienne Armangau Jun 23 '22 at 21:37
  • I'm agree for 0 as return error value.. What to return instead ? – Etienne Armangau Jun 23 '22 at 21:39
  • 2
    Converting a string to an integer, and checking for all possible errors, can be surprisingly tricky, even when you have `strtol` do most of the work for you. See [Correct usage of strtol](https://stackoverflow.com/questions/14176123). – Steve Summit Jun 23 '22 at 21:41
  • You want to convert to an unsigned integer, why do you use `strtol` unstead of `strtoul`? – Marcus Müller Jun 23 '22 at 21:43
  • If `int` and `long` have the same size, you want to make sure you listen to strto(u)l if it tells you the input number was too big. If `int` is smaller than `long`, you additionally want a test like the one you showed in your question, before you cast. So you might want to conditionally compile that test with `#if ULONG_MAX > UINT_MAX`. – Steve Summit Jun 23 '22 at 21:45
  • 1
    it would make more sense to return 0 on failure, 1 on success, and use a pointer assignment instead of returning the converted integer. – Irelia Jun 23 '22 at 21:49
  • I have added some error checks and modified the function adding an unsigned int pointer as argument and a coherent return value. – Etienne Armangau Jun 23 '22 at 22:22

1 Answers1

0

You can use :

unsigned int val = (unsigned char)bytes[0] << CHAR_BIT;
val |= (unsigned char)bytes[1];

from this link

Christian Gibbons
  • 4,272
  • 1
  • 16
  • 29
essayator
  • 18
  • 5