C Question: (const void *) vs (void *)

后端 未结 2 425
独厮守ぢ
独厮守ぢ 2021-01-30 05:36

What\'s the difference between const void * and void *? Under what circumstances can a void pointer be cast to a const void pointer?

2条回答
  •  猫巷女王i
    2021-01-30 05:56

    It's perfectly reasonable to cast a void * to a const void * and the compiler should do so implicitly behind the scenes without any thought on your part, but the other way around is dangerous and must be avoided.

    Remember, if a function takes a const pointer, then you're free to pass to it either a const or a non-const value. Saying you take a const pointer is just you declaring that the memory won't be modified by your function.

    An example: (note that the lines marked DANGER should throw a compiler error)

    const void *p_const;
    void *p_buffer;
    
    // const pointers are allowed to hold static memory
    p_const = "Foo"; // allowed
    p_buffer = "Foo"; // DANGER!!!
    
    // casting to const is implicit
    p_const = malloc(LEN); // allowed - implicit cast
    p_buffer = malloc(LEN); // allowed
    
    // casting to const implicit again
    write(STDOUT, p_const, LEN); // allowed
    write(STDOUT, p_buffer, LEN); // also allowed - implicit cast
    
    // const memory cannot be used where mutable memory is expected
    read(0, p_buffer, LEN); // allowed
    read(0, p_const, LEN); // DANGER!!
    
    // To make the above more obivous, we'll skip the intermediate variable
    // and place instead what it holds
    read(0, malloc(LEN), LEN); // allowed - useless but at least no crashes
    read(0, "foo", 4); // DANGER!!!
    

    As a general rule, if a function you write takes in a pointer to a value that you're not going to modify, then the function signature should use a const pointer. Using a pointer that isn't declared const means that the memory you're pointing to is allowed to be modified.

    Another example:

    void do_something(const void* ptr, int length);
    
    // Since the signature is a const pointer, I know I can call it like this:
    do_something("foo",4);
    

    Conversely, function calls for a non-constant pointer, then I have to allow for it:

    void do_something(void* ptr, int length);
    
    // This tells me that the function may overwrite my value.
    // The safe solution therefore looks more like this:
    
    char *myptr = char[4];
    memcpy(myptr,"foo",4);    
    do_something(myptr,4);
    

    Similarly, if you ever find yourself in a situation where you need to cast a const pointer to a non-const one, you should duplicate pointed-to value to a mutable part of memory, and pass your duplicate to the function rather than the original. If that sounds like a headache, that's because it is. If you find yourself in that situation, then you've probably done something wrong.

    Conceptually, if the variable holds a "value", then it's likely a const pointer. If, instead it holds a "buffer", then it's a non-const pointer.

    Pointers in you function signatures should always be declared const unless you intend to write to that memory. Following that rule will help you avoid disastrous problems in your program's logic.

    I didn't understand this simple rule until I had been programming for 6 years.

提交回复
热议问题