简体   繁体   中英

Confusion about pointer casts in c

char* p = (char*) malloc(8 * sizeof(char));
strcpy(p, "fungus");

for (int i = 0; i < strlen(p); i++) {
    printf("%c", p[i]);
}

char* p2 = (char*) malloc(4 * sizeof(char));
*p2 = *(uint16_t*) p;
printf("\nPointer: %c\n", p2[1]);

So I created a char* p to store the string "fungus". To my understanding, if I typecast p to a uint16_t* and dereference it, the returned value should be the first 2 bytes pointed to by p. So, p2[1] should be "u", since "u" is the second byte in the string "fungus". However, this isn't the case when I run my program. I've also tried to print p[0] + 1, but this just outputs "g". Is there an error in my logic?

To my understanding, if I typecast p to a uint16_t* and dereference it, the returned value should be the first 2 bytes pointed to by p.

This is not correct, for at least two reasons.

One, a pointer to a char might not have the alignment required for a uint16_t , and then the conversion to uint16_t is not defined by the C standard, per C 2018 6.3.2.3 7:

… If the resulting pointer is not correctly aligned70) for the referenced type, the behavior is undefined…

That will not apply in the example code in the question, since the char * is assigned from malloc , and malloc always returns an address suitably aligned for any fundamental type. However, it may apply to char * created in other ways (including by adding offsets to p , such as attempting to convert p+1 to uint16_t * ).

Two, accessing objects defined as char (including those created by writing char values to memory allocated with malloc ) as if they were uint16_t violates the aliasing rules in C 2018 6.5 7. It is possible a C implementation might reinterpret the two char as a uint16_t , but it is also possible that optimization by the compiler might transform the undefined behavior into something else.

*p2 = *(uint16_t*) p;

This code is an assignment to the single char *p2 , which is p2[0] , regardless of the fact that the right-hand side may be a 16-bit value. It does not touch p2[1] .

If *(uint16_t*) p; does reinterpret two eight-bit bytes of the string as a uint16_t , then it will produce some 16-bit value that is then assigned to the single char *p2 . If char is unsigned, this will store the low eight bits of that value as p2[0] , leaving p2[1] untouched. If it is signed, an implementation-defined conversion will be performed, and the result (if a trap does not occur) will be assigned to p2[0] , again leaving p2[1] untouched.

Then printf("\nPointer: %c\n", p2[1]); attempts to print a value that has not been initialized, since nothing has put a value in p2[1] .

You could try changing *p2 = *(uint16_t*) p; to * (uint16_t *) p2 = * (uint16_t *) p; to copy the uint16_t whole, instead of trying to cram it into a single byte.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM