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

后端 未结 2 409
独厮守ぢ
独厮守ぢ 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条回答
  • 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.

    0 讨论(0)
  • 2021-01-30 06:19

    A const void * points to memory that should not be modified.

    A void * (non-const) points to memory that could be modified (but not via the void *; you'd have to cast it first).

    When you use memmove(), the source address is cast to const void *:

    void *memmove(void *dst, const void *src, size_t nbytes);
    

    That is an illustration when a void pointer can be cast to a constant void pointer. Basically, you can do it (convert to constant) at any time when you know you are not going to modify the memory that the pointer points at. This applies to any pointer - not just void pointers.

    Converting the other way (from a constant pointer to a non-constant pointer) is a much more dangerous exercise. There's no guarantee that the memory pointed at actually is modifiable; for example, a string literal can be stored in readonly (constant) memory, and if you lose the const-ness with a cast and try to modify the string, you will likely get a segmentation fault or its equivalent - your program will stop suddenly and not under your control. This is not a good thing. So, do not change pointers from constant to non-constant without being very sure it is actually OK to lie to your compiler. Be aware that compilers do not like being lied to and can get their own back, usually at the most inconvenient moment (such as when demonstrating your program to an important prospective client in front of your boss, your boss's boss, and your boss's boss's boss).

    0 讨论(0)
提交回复
热议问题