简体   繁体   中英

How can I print the variable that a void pointer points to

I would like the function to return different types depending on different parameter values, but how can I print the variable the void pointer points to in main() ?

#include <iostream>
#include <string>
using namespace std;
void * func(int a)
{
     if (a == 1)
     {
     int param = 5;
     return &param;
     }
     else if (a == 2)
    {
    double param = 5.5;
    return &param;
    }
    else if (a == 3)
    {
    string param = "hello";
    return &param;
    }
    else
    {
    return nullptr;
    }
}
int main()
{

    void *ptr = func(3);//

    cout << ptr;// print the address not the value
    getchar();
    return 0;
 }     

param is an automatic variable. You cannot return it and use it outside its scope.

param exists only within func , if you return it, the result is Undefined Behaviour.

To fix it you can either:

  • allocate param on the heap dynamically. After you do that, you can safely return param address but you have to remember to free it when you don't need it.

Here is correction of your code

#include <iostream>
#include <string>
#include <string.h>

using namespace std;

void * func(int a)
{
    if (a == 1)
    {
        int *param = new int(5);
        return param;
    }
    else if (a == 2)
    {
        double *param = new double(5.5);
        return param;
    }
    else if (a == 3)
    {
        char *param = new char[50];
        strcpy(param, "test");
        return param;
    }

    return nullptr;
}

int main()
{
    int *ptr = (int*)func(1);
    cout << *ptr << std::endl;         // print the int value
    delete ptr;

    double *ptr2 = (double*)func(2);
    cout << *ptr2 << std::endl;        // print the double value
    delete ptr2;

    char *ptr3 = (char*)func(3);
    cout << ptr3 << std::endl;        // print the string
    delete[] ptr3;

    getchar();
    return 0;
 }

If you can use C++17, you can easily solve it by using a std::variant instead of a void * :

#include<iostream>
#include<string>
#include<variant>

std::variant<int, double, std::string, void *> func(int a) {
     if (a == 1) {
         int param = 5;
         return param;
     } else if (a == 2) {
        double param = 5.5;
        return param;
    } else if (a == 3) {
        std::string param = "hello";
        return param;
    } else {
        return nullptr;
    }
}

int main() {
    std::visit([](auto v) {
        std::cout << v << std::endl;
    }, func(3));
}

See it up and running on wandbox .

In C++11/14 you can do the same with a tagged union . The basic idea is that what you return contains enough information so that the caller can get out of it the original type.


Alternatives exist.
As an example, you could erase the type and return a pair that contains both the original (erased) variable and a pointer to function filled with an instantiation of a function template. The latter will be able to reconstruct the original variable from a void * for it knows its type.
Well, pretty much a great machinery you can avoid to use with a tagged union or a std::variant (more or less a type-safe version of a tagged union at the end of the day).

What you're returning is the address of a local variable. That variable goes out of scope when the function returns, meaning that the memory it was using could be reused. Attempting to dereference that pointer (ie access the memory it points to) invokes undefined behavior .

Even if you were returning a valid pointer, the fact that your function returns a void * means that any type information regarding what that pointer was pointing to is lost. You could print one or more bytes starting at that address, but it won't tell you what the original type was.

Even if that pointer were valid, you simply can't have enough information to force safely a cast to something and then print it. No information of its size, no information of its internal layout. So,you simply can not print what's pointed by a void*, unless you have some information prepared by hand somewhere, and force a static_cast to the known type. For example:

double x = 1.2;
int y = 5;
int f(void** output) {
    static int x;
    if ( x++ ) {
        *output = &x;
        return 1;
    }
    *output = &y;
    return 2;
}

...
void* out;
int r = f(&out);
if ( r == 1 ) cout << *(static_cast<double*>(out));
else if ( r == 2 ) cout << *(static_cast<int*>(out));

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