Есть ли лучший способ сделать путь через переменные окружения в C / C++?

Есть ли лучший способ сделать путь через переменные окружения в C / C++, чем этот?

char *S1 = std::getenv("SystemDrive");
char *S2 = std::getenv("USERNAME");
strcat(S1,"\\\\Users\\\\");
strcat(S1,S2);
strcat(S1,"\\\\");
strcat(S1,"Documents");

5 ответов

Я бы порекомендовал получить каталог профиля пользователя примерно так.

BOOL GetCurrentUserDir(LPTSTR lpszBuf, LPDWORD lpdwBuflen)
{
    HANDLE hProcessToken;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hProcessToken))
        return FALSE;

    if (!GetUserProfileDirectory(hProcessToken, lpszBuf, lpdwBuflen)) {
        CloseHandle(hProcessToken);
        return FALSE;
    }

    CloseHandle(hProcessToken);
    return TRUE;
}

Я использовал эту функцию так:

WCHAR szLocalPath[MAX_PATH];
if (!GetCurrentUserDir(szLocalPath, &cchPath))
{
    //Handle the error
}

Затем вы можете добавить остальную часть пути.

Это инкапсулирует определенные переменные среды и использует Win32 API. Это с большей вероятностью останется переносимым с течением времени.

Почему вы не используете std::string?

std::string s1 = std::getenv("SystemDrive");
s1 += "\\\\Users\\\\" + std::getenv("USERNAME") + "\\\\Documents";

Один хороший способ объединить несколько строк - это использовать snprintf:

char buf[0x10000];
int n = std::snprintf(buf, sizeof buf, "%s\\\\Users\\\\%s\\\\Documents", S1, S2);
if(static_cast<size_t>(n) >= sizeof buf)
    // Buffer is too small (if n > 0) or error

Дело в том, что snprintf не переполняет буфер и всегда завершается нулем, делает небезопасные функции strcpy, strncpy, strcat ненужным.

Не уверен, чтобы понять, что именно вам нужно. Это для создания путей из переменных среды? или получить правильные пути к системному каталогу? в последнем случае вам лучше использовать Win32 API, например: SHGetFolderPath или же SHGetKnownFolderPath,

#include <Windows.h>
#include <ShellAPI.h>
#include <KnownFolders.h>
#include <ShlObj.h>

int main()
{
    CoInitialize(NULL);
    TCHAR* path = 0;
    SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_SIMPLE_IDLIST, NULL, &path);
    // use collected 'path' here
    CoTaskMemFree(path);    // free the TCHAR object allocated by SHGetKnownFolderPath
    return 0;
}

Приведенный выше код извлекает путь к папке "Мои документы" текущего пользователя.

std::getenv устарела.

Я хотел бы использовать что-то в лайках:

char*  wSystemDrive = nullptr;
size_t wSize = 0;

bool wFree = true;

if(_dupenv_s(&wSystemDrive,&wSize,"SystemDrive") != 0 || wSystemDrive == nullptr)
{
    wFree = false;

    wSystemDrive = "C:\\"; //or anything default you want to use
}

std::string wSysteDriveString(wSystemDrive);

if(wFree)
{
    free(wSystemDrive);
}

char*  wUSERNAME = nullptr;
wSize = 0;

wFree = true;

if(_dupenv_s(&wEnv,&wSize,"wUSERNAME") != 0 || wUSERNAME == nullptr)
{
    wFree = false;

    wUSERNAME = "User";
}

std::string wUSERNAMEString(wUSERNAME);

if(wFree)
{
    free(wUSERNAME);
}

std::string wPath = wSystemDriveString + "\\Users\\" + wUSERNAMEString + "\\Documents"

Обратите внимание, что вам не нужно 4 \ (\\\\), только два (\\).

Другие вопросы по тегам