2008-09-27 2 views
217

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

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

+2

также не зависит от файловой системы? – chakrit 2008-09-27 07:19:31

+0

@chakrit: Было бы здорово. (Хотя эта проблема обычно не возникает под Windows.) – 2008-09-27 07:22:35

ответ

151

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

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; 
+3

Я думаю, что это единственный ответ, который отвечает на вопрос, и делает это как для Windows, так и для Linux. Хорошая работа. – 2008-10-14 19:31:22

+5

Boo for/proc/pid/exe - по какой-то причине не поддерживается на OS X. – 2009-07-04 07:53:01

8

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

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

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

+0

Спасибо за комментарий. Я редактировал вопрос, меня интересует путь, в котором находится исполняемый файл. – 2008-09-27 07:27:08

26

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

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

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

+6

Из документов Boost: template const Path & initial_path(); Возвращает: current_path() во время входа в main(). И current_path() is 'как будто by POSIX getcwd()'. Это не то, о чем просил запрос. – 2008-09-28 06:33:14

1

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

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

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

+9

getcwd() не делает то, что задал вопрошающий. – 2008-09-28 06:26:52

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

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

[email protected]:~/Desktop$ ./test
/home/jeremy/Desktop/./test

+0

Вам понадобится проверка, чтобы узнать, указан ли абсолютный путь в argv [0]. Но что еще более важно, что, если изображение находится через PATH? Линукс заполняет полный путь или только что находится в командной строке? – 2008-09-27 07:48:51

+0

Как указал Майк Б, это не общее решение; он работает только в очень ограниченных условиях. В основном, только когда вы запускаете команду относительным именем пути - и это не все так изящно, когда вы запускаете ../../../bin/progname, а не./ test – 2008-09-28 06:25:42

5

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

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

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

0

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

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

147

Если вы выбираете текущий каталог, когда ваша программа запускается сначала, вы фактически получаете каталог, из которого была запущена ваша программа. Сохраните значение в переменной и обратитесь к нему позже в вашей программе. Это отличное от the directory that holds the current executable program file. Это не обязательно один и тот же каталог: если кто-то запускает программу из командной строки, то программа имеет значение запустите от текущий рабочий каталог командной строки, даже если файл программы находится в другом месте.

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

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

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

Хороший ответ, но я думал, что «текущий рабочий каталог» не был тем, что нужно. – 2008-09-30 21:44:47

+2

вы должны добавить, что даже если в некоторых документах указано, что cCurrentpath может быть нулевым и будет выделен getcwd getcwd, похоже, не выделяет что-то на Mac OS и спокойно сбой вашей программы – Janusz 2009-06-30 02:52:05

3

Просто запоздал свайный здесь, .. .

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

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

0

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

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

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

3

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

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

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

Пример:

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

Это из cplusplus forum

На окнах:

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

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

у вас есть этот путь:

"path/to/file/folder" 

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

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

"./path/to/file/folder" 

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

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

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

"resources/Example.data" 

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

13

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

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 

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

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

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

Примечание:

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

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

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

14

Filesystem TS is now a standard (и поддерживается GCC 5.3+ и лязгом 3.9+), так что вы можете использовать current_path() функцию от него:

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

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

#include <experimental/filesystem> 

и связать код с -lstdc++fs флагом.

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

0

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

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

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

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

0

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