Home > OS >  Is it necessary to cast individual indices of a pointer after you cast the whole pointer in c? Why?
Is it necessary to cast individual indices of a pointer after you cast the whole pointer in c? Why?

Time:10-04

In the code below the address of ip is casted to uint8_t *. But below again each index of the casted pointer is casted to uint8_t. Why the programmer has done this? Does it make a difference if we remove all those casts that come after the initial cast? This code converts an IPv4 IP Address to an IP Number. Thank you

uint32_t Dot2LongIP(char* ipstring)
{
    uint32_t ip = inet_addr(ipstring);
    uint8_t *ptr = (uint8_t *) &ip;
    uint32_t a = 0;

    if (ipstring != NULL) {
        a =  (uint8_t)(ptr[3]);
        a  = (uint8_t)(ptr[2]) * 256;
        a  = (uint8_t)(ptr[1]) * 256 * 256;
        a  = (uint8_t)(ptr[0]) * 256 * 256 * 256;
    }
    return a;
}

CodePudding user response:

Why the programmer has done this?

Ignorance, fear, or other incompetence.

The type of ptr is uint8_t *, so the type of ptr[i] is uint8_t. Converting a uint8_t to a uint8_t has no effect. Also, putting it in parentheses has no effect.

Does it make a difference if we remove all those casts that come after the initial cast?

Yes, it makes the code smaller and clearer. It has no effect on the program semantics.

This code converts an IPv4 IP Address to an IP Number.

No, it does not, not correctly; the code is broken.

When the uint8_t value is used in multiplication with 256, the usual arithmetic conversions are applied. These promote the uint8_t to int, and then the result of the * operator is an int. For ptr[0], as two more multiplications by 256 are performed, the result remains an int. Unfortunately, if the high bit (bit 7) of ptr[0] is set, these multiplications overflow a 32-bit int. Then the behavior of the program is not defined by the C standard.

To avoid this, the value should have been cast to uint32_t. (This speaks only to getting the arithmetic correct; I make no assertion about the usefulness of taking apart an in_addr_t returned by inet_addr and reassembling it in this way.)

CodePudding user response:

I suspect that is Arduino code :)

uint32_t Dot2LongIP(char* ipstring)
{
    uint32_t ip = inet_addr(ipstring);
    
    return return nothl(ip);
}

or if you do not want to use htonl

uint32_t Dot2LongIP(char* ipstring)
{
    uint32_t ip = inet_addr(ipstring);
    
    ip = ((ip & 0xff000000) >> 24) | ((ip & 0x00ff0000) >> 8) | 
         ((ip & 0x0000ff00) << 8)  | ((ip & 0x000000ff) << 24);

    return ip;
}

CodePudding user response:

Dereferencing any index of ptr (i.e., ptr[0], ptr[1], etc) will have the type uint8_t. The casting performed on them is redundant.

  • Related