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

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

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

Ответ 1

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

Окна:

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;

Ответ 2

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

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

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

В окнах функция 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);

Ответ 3

Это из форума 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 );
}

Ответ 4

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

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

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

Ответ 5

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

Примечание:

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

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

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

Ответ 6

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

Ответ 7

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

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

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

Ответ 8

Может быть, конкатенировать текущий рабочий каталог с помощью 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
/Главная/Jeremy/Desktop/./тест

Ответ 9

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

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

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

Ответ 10

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

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

Ответ 12

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

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

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

Ответ 13

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

Пример:

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

Ответ 14

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

Ответ 15

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

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

"path/to/file/folder"

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

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

"./path/to/file/folder"

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

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

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

"resources/Example.data"

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

Ответ 16

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

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

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

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

Ответ 17

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

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

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

Ответ 18

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

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

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

Ответ 19

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

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

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

Ответ 20

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

Ответ 21

Используйте realpath() в stdlib.h так:

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

Ответ 22

Работает с С++ 11, используя экспериментальную файловую систему и С++ 14-С++ 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
}