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

208

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

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

  • 3
    файлово-независимый тоже?
  • 0
    @chakrit: Это было бы здорово. (Хотя эта проблема обычно не возникает в Windows.)
Показать ещё 6 комментариев
Теги:

20 ответов

153
Лучший ответ

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

Окна:

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;
  • 3
    Я думаю, что это единственный ответ здесь, который отвечает на вопрос, и делает это как для Windows, так и для Linux. Хорошая работа.
  • 6
    Boo for / proc / pid / exe - почему-то не поддерживается в OS X
Показать ещё 9 комментариев
140

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

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);
  • 39
    Хороший ответ, но я подумал, что «текущий рабочий каталог» - это не то, что нужно.
  • 4
    Вы должны добавить, что даже если в некоторых документах говорится, что cCurrentpath может иметь значение null и будет выделен getcwd, getcwd, похоже, не выделяет что-то в Mac OS и тихо завершает работу вашей программы.
Показать ещё 11 комментариев
27

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

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

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

  • 6
    Из документов Boost: template <class Path> const Path & initial_path (); Возвращает: current_path () во время входа в main (). И current_path () - это «как если бы POSIX getcwd ()». Это не то, что просил спрашивающий.
  • 0
    см. boost.org/doc/libs/1_46_1/libs/filesystem/v3/doc/… для надстройки 1.46.1
Показать ещё 1 комментарий
25

Это из форума 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 );
}
  • 1
    Это решение Windows не будет обрабатывать не-ANSI символы в пути. Вам, вероятно, следует использовать GetModuleFileNameW и явно преобразовать его в UTF-8 (будьте осторожны, чтобы преобразовать его обратно всякий раз, когда вам потребуется выполнить команду файловой системы).
  • 3
    Для решения Windows я получаю сообщение об error: cannot convert 'char*' to 'LPWCH {aka wchar_t*}' for argument '2' to 'DWORD GetModuleFileNameW(HMODULE, LPWCH, DWORD)' при компиляции с MinGW.
Показать ещё 2 комментария
14

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

  • 5
    По ссылочной ссылке 1-2) Returns the absolute path of the current working directory, obtained as if by POSIX getcwd. (2) returns path() if error occurs. Понижено, поскольку OP специально спрашивает о текущем пути исполняемого файла, а не о текущем рабочем каталоге.
13

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

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

  • 0
    Да, это работает и в Windows. Я думаю, что это лучшее решение. Насколько я знаю, argv [0] всегда сохраняет путь к исполняемому файлу.
  • 1
    argv[0] - очень хорошая идея, но, к сожалению, я получаю в Linux "./my_executable_name" или "./make/my_executable_name". То, что я получаю, полностью зависит от того, как я его запускаю
8

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

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

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

  • 0
    Спасибо за комментарий. Я отредактировал вопрос, меня интересует путь, где находится исполняемый файл.
7

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

  • 0
    Вам понадобится проверить, указан ли абсолютный путь в argv [0]. Но что более важно, что, если изображение находится через PATH? Линукс заполняет полный путь или только то, что в командной строке?
  • 0
    Как указал Майк Б., это необщее решение; это работает только в некоторых очень ограниченных обстоятельствах. В основном, только когда вы запускаете команду по относительному пути - и это не так уж и элегантно, когда вы запускаете ../../../bin/progname вместо ./test
Показать ещё 3 комментария
6

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

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

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

5

Для Win32 GetCurrentDirectory должен сделать трюк.

  • 0
    cout << ExePath () << endl; - Так легко, спасибо
3

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

Пример:

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

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

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

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

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

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

1

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

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

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

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

1

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

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

"path/to/file/folder"

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

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

"./path/to/file/folder"

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

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

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

"resources/Example.data"

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

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

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

0

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

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

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

0

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

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

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

0

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

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

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

  • 10
    getcwd () не делает то, что спросил спрашивающий.
  • 0
    не в том, что принятый ответ использует getcwd (), или я не просто понимаю?
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню