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

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

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

20 ответов


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

окна:

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] = '';
return bytes;

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

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

поскольку вы создаете программу 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] = ''; /* not really required */

printf ("The current working directory is %s", cCurrentPath);

Это форум cplusplus

на windows:

#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 );
}

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

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

IMHO это так близко, как вы можете получить, с хорошей кармой (Boost-это хорошо установленный набор высококачественных библиотек)


файловая система 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, то читать это.


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("\"));

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


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

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


может объединить текущий рабочий каталог с 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$ ./ тест
/ главная / Джереми / рабочий стол/./ тест


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

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

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


Для Win32 GetCurrentDirectory следует сделать трюк.


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

пример:

int main()
{
    system("dir");
    system("pause"); //this wait for Enter-key-press;
    return 0;
}

просто запоздало кучи здесь...

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

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


в Windows Самый простой способ-использовать


#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);
}

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

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

что требуется, чтобы получить Ваш идентификатор процесса и проанализировать путь к имя

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


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

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

"path/to/file/folder"

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

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

"./path/to/file/folder"

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

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

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

"resources/Example.data"

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


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

в Windows вы можете использовать методов _getcwd() Как использовать getcwd () была прекращена.

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


увеличить файловую систему initial_path() ведет себя как , и не делает то, что вы хотите сами по себе, но добавляет argv[0] чтобы любой из них должен это сделать.

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

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


As Минок упомянутый, нет такой функциональности, указанной в стандарте ini C или стандарте C++. Это считается чисто специфичной для ОС функцией и указывается, например, в стандарте POSIX.

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

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


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