Home > database >  Why can I pass CHAR[] as a LPSTR parameter?
Why can I pass CHAR[] as a LPSTR parameter?

Time:02-03

This is working for me...

std::string GetProgramDataPath() {

    CHAR path[MAX_PATH];
    HRESULT hr = SHGetFolderPathA(nullptr, CSIDL_COMMON_APPDATA, nullptr, 0, path); // path accepted as LPSTR parameter?

    if (SUCCEEDED(hr)) {
        return std::string(path); // then automatically cast to const char*?
    }
    else {
        return std::string();
    }
}

...but I don't know why. I try to pass LPSTR, but I get:

Error C4700 "uninitialized local variable 'path' used"

I look up how to initialize LPSTR and come up with this:

std::string GetProgramDataPath() {

    LPSTR path = new CHAR[MAX_PATH];
    HRESULT hr = SHGetFolderPathA(nullptr, CSIDL_COMMON_APPDATA, nullptr, 0, path);

    if (SUCCEEDED(hr)) {
        std::string strPath(path);
        delete[] path;
        return std::string(strPath);
    }
    else {
        delete[] path;
        return std::string();
    }
}

Is this the 'correct' code? With new and delete it seems wrong. Am I doing something unsafe by just using CHAR[]? How come it works instead of LPSTR? I believe it has something to do with the "equivalence of pointers and arrays" in C, but it seems there are some automatic conversions from CHAR[] to LPSTR to const char * in this code I don't understand.

CodePudding user response:

Instead of managing the memory your self with new and delete I'd use a std::string instead and let it manage the memory.

static std::string GetProgramDataPath()
{
    std::string buffer(MAX_PATH, '\0');
    const HRESULT result = SHGetFolderPathA
    (
        nullptr, 
        CSIDL_COMMON_APPDATA, 
        nullptr, 
        0, 
        buffer.data()
     );

     if (SUCCEEDED(result))
     {
         // Cut off the trailing null terminating characters.
         // Doing this will allow you to append to the string
         // in the position that you'd expect.
         if (const auto pos{ buffer.find_first_of('\0') }; pos != std::string::npos)
             buffer.resize(pos);

         // Here is how you can append to the string further.
         buffer.append(R"(\Some\Other\Directory)");
         return buffer;
     }

     buffer.clear();
     return buffer;
}

CodePudding user response:

This is working for me...but I don't know why.

LPSTR is just an alias for CHAR* (aka char*):

typedef CHAR *LPSTR;

In certain contexts, a fixed-sized CHAR[] (aka char[]) array will decay into a CHAR* (aka char*) pointer to its 1st element, such as when passing the array by value in a function parameter, as you are doing.

I try to pass LPSTR, but I get Error C4700 "uninitialized local variable 'path' used".

Because LPSTR is just a pointer, and you likely did not point it at anything meaningful.

Is this the 'correct' code?

Technically yes, that will work (though return std::string(strPath) should be return strPath instead). However, you should consider using std::string or std::vector<char> instead to manage memory for you, don't use new[]/delete[] directly, eg:

std::string GetProgramDataPath() {

    std::vector<char> path(MAX_PATH);
    HRESULT hr = SHGetFolderPathA(nullptr, CSIDL_COMMON_APPDATA, nullptr, 0, path.data());

    if (SUCCEEDED(hr)) {
        return std::string(path.data());
    }

    return std::string();
}

Am I doing something unsafe by just using CHAR[]?

No.

How come it works instead of LPSTR?

Because CHAR[] decays into the same type that LPSTR is an alias of.

it seems there are some automatic conversions from CHAR[] to LPSTR to const char * in this code.

Correct.

  • Related