Как получить каталог, из которого запускается программа? - PullRequest
248 голосов
/ 27 сентября 2008

Существует ли платформо-независимый и файлово-независимый метод для получения полного пути к каталогу, из которого программа работает с использованием C / C ++? Не путать с текущим рабочим каталогом. (Пожалуйста, не предлагайте библиотеки, если они не стандартные, такие как clib или STL.)

(Если нет метода, независимого от платформы / файловой системы, приветствуются предложения, которые работают в Windows и Linux для конкретных файловых систем.)

Ответы [ 21 ]

169 голосов
/ 13 октября 2008

Вот код для получения полного пути к исполняемому приложению:

Windows:

int bytes = GetModuleFileName(NULL, pBuf, len);
if(bytes == 0)
    return -1;
else
    return bytes;

Linux:

char szTmp[32];
sprintf(szTmp, "/proc/%d/exe", getpid());
int bytes = MIN(readlink(szTmp, pBuf, len), len - 1);
if(bytes >= 0)
    pBuf[bytes] = '\0';
return bytes;
163 голосов
/ 28 сентября 2008

Если вы извлекаете текущий каталог при первом запуске вашей программы, то у вас фактически есть каталог, из которого была запущена ваша программа. Сохраните значение в переменной и обратитесь к нему позже в вашей программе. Это отличается от каталога, в котором находится текущий исполняемый файл программы . Это не обязательно тот же каталог; если кто-то запускает программу из командной строки, то программа запускается из текущего рабочего каталога командной строки, даже если файл программы находится в другом месте.

getcwd является функцией POSIX и поддерживается "из коробки" всеми POSIX-совместимыми платформами. Вам не нужно было бы делать ничего особенного (кроме указания правильных заголовков unistd.h в Unix и direct.h в Windows).

Поскольку вы создаете программу на C, она свяжется со стандартной библиотекой времени выполнения c, с которой связаны ВСЕ процессы в системе (исключены специально созданные исключения), и будет включать эту функцию по умолчанию. CRT никогда не считается внешней библиотекой, поскольку она предоставляет базовый стандартный интерфейс, совместимый с ОС.

В windows функция getcwd устарела в пользу _getcwd. Я думаю, вы могли бы использовать это таким образом.

#include <stdio.h>  /* defines FILENAME_MAX */
#ifdef WINDOWS
    #include <direct.h>
    #define GetCurrentDir _getcwd
#else
    #include <unistd.h>
    #define GetCurrentDir getcwd
 #endif

 char cCurrentPath[FILENAME_MAX];

 if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)))
     {
     return errno;
     }

cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */

printf ("The current working directory is %s", cCurrentPath);
36 голосов
/ 23 октября 2013

Это с форума cplusplus

На окнах:

#include <string>
#include <windows.h>

std::string getexepath()
{
  char result[ MAX_PATH ];
  return std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) );
}

В Linux:

#include <string>
#include <limits.h>
#include <unistd.h>

std::string getexepath()
{
  char result[ PATH_MAX ];
  ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX );
  return std::string( result, (count > 0) ? count : 0 );
}

В HP-UX:

#include <string>
#include <limits.h>
#define _PSTAT64
#include <sys/pstat.h>
#include <sys/types.h>
#include <unistd.h>

std::string getexepath()
{
  char result[ PATH_MAX ];
  struct pst_status ps;

  if (pstat_getproc( &ps, sizeof( ps ), 0, getpid() ) < 0)
    return std::string();

  if (pstat_getpathname( result, PATH_MAX, &ps.pst_fid_text ) < 0)
    return std::string();

  return std::string( result );
}
28 голосов
/ 27 сентября 2008

Если вам нужен стандартный способ без библиотек: Нет. Вся концепция каталога не включена в стандарт.

Если вы согласны с тем, что некоторая (переносимая) зависимость от почти стандартной библиотеки в порядке: используйте библиотеку файловой системы Boost и запросите initial_path () .

ИМХО, это как можно ближе, с хорошей кармой (Boost - это устоявшийся высококачественный набор библиотек)

17 голосов
/ 15 августа 2015

Я знаю, что уже очень поздно бросать ответ на этот вопрос, но я обнаружил, что ни один из ответов не был для меня столь же полезным, как мое собственное решение. Очень простой способ получить путь от вашего CWD до вашей папки bin выглядит так:

int main(int argc, char* argv[])
{
    std::string argv_str(argv[0]);
    std::string base = argv_str.substr(0, argv_str.find_last_of("/"));
}

Теперь вы можете просто использовать это как базу для вашего относительного пути. Так, например, у меня есть эта структура каталогов:

main
  ----> test
  ----> src
  ----> bin

и я хочу скомпилировать мой исходный код в bin и написать журнал для проверки. Я могу просто добавить эту строку в свой код.

std::string pathToWrite = base + "/../test/test.log";

Я попробовал этот подход в Linux, используя полный путь, псевдоним и т. Д., И он работает просто отлично.

Примечание:

Если вы находитесь в Windows, вы должны использовать '\' в качестве разделителя файлов, а не '/'. Вам тоже придется избежать этого, например:

std::string base = argv[0].substr(0, argv[0].find_last_of("\\"));

Я думаю, что это должно сработать, но не проверялось, поэтому мы будем благодарны за комментарии, если это сработает, или исправление, если нет.

17 голосов
/ 17 января 2016

Файловая система TS теперь является стандартной (и поддерживается gcc 5.3+ и clang 3.9+), поэтому вы можете использовать из нее функцию current_path():

std::string path = std::experimental::filesystem::current_path();

В gcc (5.3+) для включения файловой системы необходимо использовать:

#include <experimental/filesystem>

и свяжите свой код с флагом -lstdc++fs.

Если вы хотите использовать файловую систему с Microsoft Visual Studio, тогда прочитайте это .

9 голосов
/ 27 сентября 2008

Нет, стандартного способа нет. Я считаю, что стандарты C / C ++ даже не учитывают существование каталогов (или других организаций файловой системы).

В Windows GetModuleFileName () вернет полный путь к исполняемому файлу текущего процесса, если для параметра hModule установлено значение NULL . Я не могу помочь с Linux.

Также вы должны уточнить, хотите ли вы, чтобы текущий каталог или каталог, в котором находится образ программы / исполняемый файл. В этом смысле ваш вопрос немного двусмысленен в этом вопросе.

8 голосов
/ 27 сентября 2008

Возможно объединить текущий рабочий каталог с argv [0]? Я не уверен, что это будет работать в Windows, но работает в Linux.

Например:

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char **argv) {
    char the_path[256];

    getcwd(the_path, 255);
    strcat(the_path, "/");
    strcat(the_path, argv[0]);

    printf("%s\n", the_path);

    return 0;
}

При запуске выдает:

jeremy @ jeremy-desktop: ~ / Desktop $ ./test
/home/jeremy/Desktop/./test

6 голосов
/ 03 июня 2013

В Windows самым простым способом является использование функции _get_pgmptr в stdlib.h для получения указателя на строку, представляющую абсолютный путь к исполняемому файлу, включая имя исполняемого файла.

char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe
6 голосов
/ 27 сентября 2008

Для этой цели нельзя использовать argv [0], обычно он содержит полный путь к исполняемому файлу, но необязательно - процесс может быть создан с произвольным значением в поле.

Также учтите, что текущий каталог и каталог с исполняемым файлом - это две разные вещи, поэтому getcwd () вам тоже не поможет.

В Windows используйте GetModuleFileName (), в Linux читайте / dev / proc / procID / .. файлы.

...