简体   繁体   中英

Use of char* over void* in pointer arithmetic

I am going through this code for learning purposes and have a question about this line :

return (char*)desc + sizeof *desc;

Why is desc cast to char* ? I tried to mimic it with my own code:

#include <stdio.h>
#include <stdlib.h>

struct Test {
    int value;
};

int main() {

    struct Test* test = malloc(sizeof test);

    struct Test* test1 = (void*)test + sizeof *test;
    test1->value = 1;
    printf("%d\n", test1->value);

    struct Test* test2 = (void*)test1 + sizeof *test;
    test2->value = 10;
    printf("%d\n", test2->value);

}

This also works. But, what is the difference? Why is char* used?

Note: I used void* just to see if that works. As char* has nothing to do with the struct in question, I simply thought, "What if I use void* over there?". A more specific question could be, why not int* or float* & why char* is used?

Why Pointers to Characters Are Used

Why is desc cast to char*? … As char* has nothing to do with the struct in question…

In C, every object except a bit-field is composed of a sequence of bytes. 1 Converting the address of an object to char * yields a pointer to the first byte of the object, and you can access the individual bytes of the object using that pointer.

In standard C, pointer arithmetic uses units of the pointed-to type. For a pointer p of type struct Test , p+1 points to the next structure after p , p+2 points to the structure after that, and so on. For a pointer q of type char * , q+1 points to the next char after q, q+2 points to char after that, and so on.

Thus, to access the individual bytes of an object, you can convert its address to a char * and use that.

Why Other Kinds of Pointers Are Not Used

A more specific question could be, why not int* or float* & why char* is used?

char * is used because all objects in C, except bit-fields, are defined to be represented as sequences of bytes. They are not necessarily sequences of int or float . unsigned char * and signed char * may also be used, and unsigned char * may be preferable due to complications from sign issues.

The C standard has special rules about accessing objects using character pointers, so it guarantees that accessing the bytes of an object this way will work. In contrast, accessing objects using int * or float * may not work. The compiler is allowed to expect that a pointer to an int will not be used to access a float object, and, when it is generating machine instructions for a program, it may write those instructions based on that expectation. Using a character pointer prevents the compiler from assuming that a char * does not point to the same place as another kind of pointer.

Why Pointers to Void Work

Note: I used void* just to see if that works.

For pointer arithmetic to work, the compiler needs to know the size of the pointed-to object. When 1 is added to a pointer to a struct Test , the compiler needs to know how many bytes to adjust the internal address by.

void is an incomplete type. There are no void objects, and void has no size. (The size is not zero. There is no size.) Because of this, the C standard does not define any meaning for p+1 when p is a void * .

However, GCC defines arithmetic on void * as an extension . It works as if void had a size of 1 byte. Clang supports this too.

Because of this extension, doing arithmetic with void * pointers is essentially the same as doing arithmetic with char * pointers.

This extension is unnecessary; any code doing arithmetic on void * could be rewritten to use char * instead. Sometimes this requires extra casts to convert pointer types, and that could be the reason the extension was added to GCC (to reduce the amount of code required and make it look better).

You can disable this extension with the switches -Werror -Wpointer-arith , or you can generally request closer conformance to standard C with -Werror -std=c18 -pedantic . I used -Werror -std=c18 -pedantic whenever possible, and I recommend it.

Footnote

1 Bit-fields are sequences of bits that are held in some larger container of bytes and may happen to coincide with bytes.

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