0

Usually, this is caught by the compiler. But using a cast to a function pointer we can manage to do this.

I may not have worded it properly, here is an example to better illustrate my question:

void printintp(int *ip)
{
    printf("pointer = %p\n", ip);
    printf("*pointer = %d\n", *ip);
}

void printint(int &i)
{
    printf("int = %d\n", i);
}

int main()
{
    int a = 555;
    //int &irp = &a;   // ERROR 1
    void (*f)(void *);

    //printint((int &) &a);   // ERROR 2
    f = (void (*)(void *))printintp;
    f(&a);
    f = (void (*)(void *))printint;
    //printint(&a);       // ERROR 3 (invalid conversion of `int *` to `int`)
    f(&a);              // GOOD (why?)
    return 0;
}

And the output is ofcourse what one would expect:

pointer = 0x7ffd01995bf4
*pointer = 555
int = 555

So my question refines to these: Why is passing pointer &a to the object-expecting function printint OK? Is this undefined behavior that just happens to work on my implementation? If not, How does parameter int &i get bound to object a if we just pass its address and why does it reject what I marked as ERROR 2?

PS: The best I could find on the issue is this which claims both printintp and printint are "functionally the same", although, in practice, the function calls are different (printintp(&a) and printint(a)).

PS2: Please note that I'm not asking the difference between a pointer and a reference, which is already very explained here.

zazke
  • 113
  • 2
  • 6

1 Answers1

3

Is this undefined behavior that just happens to work on my implementation?

Yes. Most compilers implement a reference using a pointer under the hood, but that is not dictated by the standard.

Standard syntax does not allow a pointer to be assigned as-is to a reference, and vice versa, hence the compiler errors on those statements.

Casting everything to void*, all bets are off on type safety. Using a C-style type cast, you can get away with just about anything. You are basically telling the compiler that you know what you are doing, so it should just accept it and be quiet. That is why such type-casts can be dangerous when you don't know what you are really doing, and should be avoided unless absolutely necessary. If you must cast, prefer C++-style type casts instead (static_cast, reinterpret_cast, etc). At least then, you won't give up quite as much type safety.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770