it-swarm.com.ru

Как получить каталог, из которого запускается программа?

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

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

245
Ashwin Nanjappa

Вот код, чтобы получить полный путь к исполняемому приложению:

Окна:

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;
164
Mike

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

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);
159
computinglife

Это с форума 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 );
}
34
Octopus

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

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

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

28
Thorsten79

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

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

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

#include <experimental/filesystem>

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

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

18
Marqin

Я знаю, что уже слишком поздно, чтобы дать ответ на этот вопрос, но я обнаружил, что ни один из ответов не был настолько полезен для меня, как мое собственное решение. Очень простой способ получить путь от вашего 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("\\"));

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

16
Sam Redway

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

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

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

8
Michael Burr

Может быть, объединить текущий рабочий каталог с 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

7
Jeremy Ruten

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

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

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

6
eugensk00

Для Win32 GetCurrentDirectory следует сделать свое дело.

5
Torbjörn Gyllebring

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

char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe
5
Adam Yaxley

Просто чтобы запоздало навалиться на ...

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

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

3
Minok

Для системы Windows на консоли вы можете использовать команду system (dir). И консоль дает вам информацию о каталоге и т.д. Прочтите о команде dir по адресу cmd. Но для Unix-подобных систем я не знаю ... Если эта команда запущена, прочитайте команду bash. ls не отображает каталог ...

Пример:

int main()
{
    system("dir");
    system("pause"); //this wait for Enter-key-press;
    return 0;
}
3
Alexey1993
#include <windows.h>
using namespace std;

// The directory path returned by native GetCurrentDirectory() no end backslash
string getCurrentDirectoryOnWindows()
{
    const unsigned long maxDir = 260;
    char currentDir[maxDir];
    GetCurrentDirectory(maxDir, currentDir);
    return string(currentDir);
}
2
freezotic

Команда linux bash progname сообщит путь к программе.

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

Требуется получить идентификатор вашего процесса и разобрать путь к имени. 

В моей программе я хочу узнать, была ли программа Выполнена из каталога bin пользователя или из другого каталога по пути Или из/usr/bin./usr/bin будет содержать поддерживаемую версию . Мне кажется, что в Linux есть единственное решение, которое является переносимым.

1
Leslie Satenstein

Для относительных путей вот что я сделал. Мне известно о возрасте этого вопроса, я просто хочу предложить более простой ответ, который работает в большинстве случаев:

Скажем, у вас есть такой путь:

"path/to/file/folder"

По некоторым причинам, исполняемые файлы Linux, созданные в Eclipse, прекрасно работают с этим. Тем не менее, окна становятся очень запутанными, если использовать такой путь для работы!

Как указывалось выше, есть несколько способов получить текущий путь к исполняемому файлу, но самый простой способ, который я нахожу, работает в большинстве случаев - это добавление к ПЕРЕДНЕМУ вашего пути:

"./path/to/file/folder"

Просто добавив "./", вы получите сортировку! :) Затем вы можете начать загрузку из любой директории, которую пожелаете, при условии, что она выполняется с самим исполняемым файлом.

Правка: Это не будет работать, если вы попытаетесь запустить исполняемый файл из code :: blocks, если используется среда разработки, так как по какой-то причине code :: blocks не загружает вещи правильно ...: D

Правка 2: Некоторые новые вещи, которые я обнаружил, состоят в том, что если вы указываете статический путь, подобный этому, в своем коде (при условии, что вам нужно загрузить Example.data):

"resources/Example.data"

Если вы затем запускаете свое приложение из фактического каталога (или в Windows, вы делаете ярлык и устанавливаете рабочий каталог в каталог вашего приложения), то оно будет работать следующим образом ........ Имейте это в виду при отладке проблем, связанных с отсутствием пути к ресурсам/файлам. (Особенно в IDE, которые устанавливают неправильный рабочий каталог при запуске исполняемого файла сборки из IDE)

1
FuzzyQuills

Как упоминалось в Minok, в стандарте i C или стандарте C++ такой функциональности не существует. Это считается исключительно функцией ОС и определяется, например, в стандарте POSIX.

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

Хорошая альтернатива, которую я бы порекомендовал, - это коллекция из 100% только заголовков библиотеки STLSoft C++Мэтью Уилсон (автор книг о C++, которые необходимо прочитать). Портативный фасад PlatformSTL предоставляет доступ к системно-зависимому API: WinSTL для Windows и UnixSTL для Unix, поэтому это портативное решение. Все системные элементы определяются с использованием признаков и политик, поэтому это расширяемая структура. Конечно, есть библиотека файловой системы.

0
mloskot

Функция Boost Filesystem initial_path() ведет себя как getcwd() POSIX, и при этом сама по себе не выполняет то, что вам нужно, но добавление argv[0] к любому из них должно сделать это.

Вы можете заметить, что результат не всегда хорош - вы можете получить такие вещи, как /foo/bar/../../baz/a.out или /foo/bar//baz/a.out, но я считаю, что он всегда приводит к правильному пути с именем исполняемого файла (обратите внимание, что последовательные косые черты в пути свернуты в единицу).

Ранее я писал решение с использованием envp (третий аргумент main(), который работал в Linux, но не казался работоспособным в Windows, поэтому я, по сути, рекомендую то же решение, что и кто-то другой ранее, но с дополнительным объяснением того, почему оно на самом деле правильно, даже если результаты не красивые.

0
John Zwinck

На платформах POSIX вы можете использовать getcwd () .

В Windows вы можете использовать _getcwd () , так как использование getcwd () устарело.

Для стандартных библиотек, если бы Boost был достаточно стандартным для вас, я бы предложил Boost :: filesystem, но, похоже, они удалили нормализацию пути из предложения. Возможно, вам придется подождать, пока TR2 не станет легко доступным для полностью стандартного решения.

0
Fruny

Решение для библиотеки (хотя я знаю, что об этом не просили) . Если вы используете Qt: QCoreApplication::applicationDirPath()

0
Joachim

Используйте realpath() в stdlib.h следующим образом:

char *working_dir_path = realpath(".", NULL);
0
Manabu Nakazawa

Работает с C++ 11, используя экспериментальную файловую систему и C++ 14-C++ 17, а также с официальной файловой системой.

application.h:

#pragma once

//
// https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros
//
#ifdef __cpp_lib_filesystem
#include <filesystem>
#else
#include <experimental/filesystem>

namespace std {
    namespace filesystem = experimental::filesystem;
}
#endif

std::filesystem::path getexepath();

application.cpp:

#include "application.h"
#ifdef _WIN32
#include <windows.h>    //GetModuleFileNameW
#else
#include <limits.h>
#include <unistd.h>     //readlink
#endif

std::filesystem::path getexepath()
{
#ifdef _WIN32
    wchar_t path[MAX_PATH] = { 0 };
    GetModuleFileNameW(NULL, path, MAX_PATH);
    return path;
#else
    char result[PATH_MAX];
    ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
    return std::string(result, (count > 0) ? count : 0);
#endif
}
0
TarmoPikaro