Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC: dereferencing ‘void *’ pointer while taking address

I noticed GCC triggers:

warning: dereferencing ‘void *’ pointer

While taking the address of a dereferenced void expression like:

int main()
{
    void *p = "abcdefgh";

    printf("%p\n", p);
    printf("%p\n", &*p);

    return 0;
}

However, the expression p is equivalent to &*p according to the C standard:

§6.5.3.2 Address and indirection operators

The unary & operator returns the address of its operand. If the operand has type ‘‘type’’, the result has type ‘‘pointer to type’’. If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue.

It is also important to know that Clang does not trigger this warning.

DISCLAIMER

For a better explanation, consider this:

int main()
{
    int *p = NULL;

    printf("%p\n", (void *) p);
    printf("%p\n", (void *) &*p);

    return 0;
}

This code compiles and runs perfectly with both Clang and GCC. The C standard is clear about void pointers, you can dereference them (thus getting a void value) but you cannot use the result of the expression.

like image 806
explogx Avatar asked Jan 25 '19 23:01

explogx


People also ask

Can you dereference void *?

Some Interesting Facts: 1) void pointers cannot be dereferenced.

When can we dereference a void pointer?

Example 1: C++ Void Pointer Here, the pointer ptr is given the value of &f . The output shows that the void pointer ptr stores the address of a float variable f . As void is an empty type, void pointers cannot be dereferenced.

What is a void pointer can you dereference a void pointer without knowing its type?

You cannot. Dereferencing a void pointer requires an explicit cast beforehand. You can ofcourse cast it to any particular type and then dereference it without knowing its original type, but why you would want to do that is beyond me.

How do you dereference a void pointer in C++?

C++ void pointer is used to store the address of any other data type. Void pointer is declared with void*. We can't dereference the void pointer without reassigning this pointer to another variable type.


1 Answers

I am assuming the question here is "Why is that?/What gives?". In which case it's really a bit of a standards-wording / flexibility-for-compiler-developers issue.

Strictly speaking *(void*) is always bad, and the compiler is right to warn you. In practice, as you rightly point out the pointer is never really actually dereferenced, in the evaluate what you see at what it points to way, so a naive implementation of a compiler would have no problem seeing this the way you do, and glossing over this and saying "pointers: they're numbers right? this one is 0xFFF....".

In practice though sometimes this is not the case. Sometimes compilers get pretty smart. No good examples spring to mind but that's not the point.

A couple of things I think might be worth noting with regards to "it's never evaluated":

The reason compilers are given the freedom to do what they want is partly to ease the process of compilation itself not just the output better implementations. It may be that the next compiler you point this at will say no. Just because it's easier and it doesn't have to.

Secondly that's not really the point of warnings. If I saw this in a code review:

int i = 3;
if (3-i) {
    ((int*)(NULL)) += 4;
}

my reaction would not be: "Oh okay that's fine, its not evaluated." but "Whoa hang on a second: why?". This is what the compiler does too. It's telling you it thinks you are likely to have done something you might want to reconsider, in this case calling a const char * a void *. I, for one, agree with gcc.

like image 77
drjpizzle Avatar answered Nov 15 '22 00:11

drjpizzle