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

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

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

Если вы не сможете надежно извлечь путь из argv[0], метод будет сильно зависеть от ОС.

David R Tribble 28.01.2010 03:42

Просто чтобы уточнить: «текущий каталог» или «каталог, из которого запущена программа» (в терминологии вопроса) - это каталог, в котором находится файл изображения программы (файл ~ .exe), и 'текущий каталог работающий' - это каталог, который заполняется автоматически, если программа использует относительные пути?

colemik 24.04.2013 13:53

Когда вы используете #include <windows.h>, Windows автоматически помещает char* в путь к исполняемому файлу в _pgmptr. Вам не нужно вызывать дополнительные функции или предполагать нежелательную загрузку, если вы работаете только в Windows.

rsethc 01.05.2013 05:38

Это ответ на ваш первоначальный вопрос? github.com/gpakosz/whereami

Gregory Pakosz 05.06.2015 18:20

Хотя комментарий был сделан три года назад, я хотел бы расширить комментарий rsethc о _pgmptr. В документации MSDN указано, что переменные _pgmptr и _wpgmptr устарели, и вместо них следует использовать функцию _get_pgmptr(char**) или _get_wpgmptr(wchar_t**). MSDN

Hydranix 06.03.2016 02:44

Я пробовал версию для Windows с использованием Borland C++ Builder 6, параметры pBuf и len не известны. Неопределенный символ. Какие заголовки я должен включить?

AirCraft Lover 24.05.2019 17:46

Если у вас современный компилятор, вы можете проверить stackoverflow.com/a/60804126/3246135.

nilo 05.06.2020 22:15
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
278
7
523 804
24
Перейти к ответу Данный вопрос помечен как решенный

Ответы 24

Для Win32 GetCurrentDirectory должен помочь.

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

McLeary 16.04.2020 11:34

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

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

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

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

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

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

Из документации Boost: template <class Path> const Path & initial_path (); Возвращает: current_path () во время входа в main (). А current_path () - это «как если бы POSIX getcwd ()». Это не то, что просил вопрошающий.

Jonathan Leffler 28.09.2008 10:33

см. boost.org/doc/libs/1_46_1/libs/filesystem/v3/doc/… для повышения 1.46.1

moala 22.04.2011 19:43

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

jpo38 22.06.2016 16:34

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

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

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

getcwd () не выполняет то, что спросил спрашивающий.

Jonathan Leffler 28.09.2008 10:26

Разве в принятом ответе не используется getcwd (), или я просто не понимаю?

Sнаđошƒаӽ 19.04.2015 20:24

Я проголосовал "за", потому что вы первым пришли с тем, что считается правильным ответом.

Arnaud 26.06.2015 15:43

Этот ответ даже не пытается ответить на вопрос. Стыдно писать это.

SmallChess 22.03.2018 03:14

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

Вам нужно будет проверить, указан ли абсолютный путь в argv [0]. Но что еще более важно, что, если изображение находится через PATH? Заполняет ли linux полный путь или только то, что указано в командной строке?

Michael Burr 27.09.2008 11:48

Как заметил Майк Б., это не общее решение; он работает только в очень ограниченных обстоятельствах. По сути, только когда вы запускаете команду по относительному имени пути - и это не так уж элегантно, когда вы запускаете ../../../bin/progname вместо ./test

Jonathan Leffler 28.09.2008 10:25

Если вы разрешите возможный относительный путь argv [0] по сравнению с текущим каталогом (потому что argv [0] может быть «../../myprogram.exe»), это, вероятно, самый безопасный способ ответить на вопрос. Он всегда будет работать и портативен (работает даже на Android!).

jpo38 22.06.2016 17:02

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

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

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

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

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

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

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

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

Хороший ответ, но я подумал, что «текущий рабочий каталог» - это не то, что нужно.

Michael Burr 01.10.2008 01:44

вы должны добавить, что даже если в некоторых документах говорится, что cCurrentpath может быть нулевым и будет выделен getcwd, getcwd, похоже, не выделяет что-то в Mac OS и незаметно завершает работу вашей программы

Janusz 30.06.2009 06:52

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

andrew cooke 10.12.2009 16:43

Произошла небольшая ошибка, но, к сожалению, я пока не могу ее редактировать .. строка 10: cCurrentpath: должно быть cCurrentPath

Lipis 20.12.2009 17:56

IMO в Windows следует избегать функций с именем POSIXy (некоторые из которых начинаются с подчеркивания). Это не настоящие Windows API, а скорее CRT. API Windows, который вы хотите использовать, - это GetCurrentDirectory (). msdn.microsoft.com/en-us/library/aa364934(VS.85).aspx

asveikau 28.01.2010 03:33

Мне нужно было добавить #include <errno.h> и использовать char вместо TCHAR, чтобы это работало.

Alec Jacobson 19.05.2012 18:08

Зачем делить на sizeof (TCHAR)? Разве вы не хотите разделить на sizeof (char)? Кроме того, не всегда ли размер char должен быть равен 1? Если так, то деление показалось бы излишним.

allyourcode 03.08.2012 00:17

@allyourcode TCHAR принимает значение char или wchar_t в зависимости от того, используете ли вы Ascii или Unicode. sizeof (wchar_t) равен 2 в Windows.

Jerome 16.08.2012 01:34

Просто чтобы уточнить: «текущий каталог» - это каталог, в котором находится файл изображения программы (файл ~ .exe), а «текущий каталог работающий» - это каталог, который автоматически заполняется, если программа использует относительные пути?

colemik 24.04.2013 13:51

Ответ Майка правильный. «Текущий каталог» не всегда совпадает с каталогом, из которого запущен двоичный файл. Например, если приложение работает как служба в Windows, текущий каталог, вероятно, будет C: \ Windows \ System32, тогда как двоичный каталог будет другим.

Lucky Luke 14.02.2014 20:32

@LuckyLuke: Или когда приложение запускается с помощью ярлыка (.lnk), который позволяет вам указать текущий рабочий каталог. Так что запрос CWD перед тем, как делать что-либо еще в вашем процессе, тоже бесполезен. Этот ответ просто не отвечает на вопрос.

IInspectable 16.05.2016 16:09

Он должен быть _WIN32 вместо WINDOWS, WINDOWS больше похож на компилятор.

Beyondo 16.04.2018 23:52

Возможно, это не то, о чем просил человек, но это ответ, который я искал в Google и хотел ^ _ ^ (нужно было отладить код, и это отлично работает для меня) Спасибо!

Tim 27.04.2018 18:37
Ответ принят как подходящий

Вот код для получения полного пути к исполняющему приложению:

Окна:

char pBuf[256];
size_t len = sizeof(pBuf); 
int bytes = GetModuleFileName(NULL, pBuf, len);
return bytes ? bytes : -1;

Linux:

int bytes = MIN(readlink("/proc/self/exe", pBuf, len), len - 1);
if (bytes >= 0)
    pBuf[bytes] = '\0';
return bytes;

Я думаю, что это единственный ответ на этот вопрос, причем как для Windows, так и для Linux. Хорошая работа.

Frank Szczerba 14.10.2008 23:31

Boo для / proc / pid / exe - по какой-то причине не поддерживается в OS X.

Chris Lutz 04.07.2009 11:53

Когда я вижу код, который смотрит на /proc, часть меня немного умирает. Весь мир - это не Linux, и даже на этой одной платформе /proc следует рассматривать как подлежащую изменению от версии к версии, от архива к архитектуре и т. д.

asveikau 28.01.2010 03:29

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

asveikau 28.01.2010 03:36

@asveikau argv[0] показывает команду, используемую для запуска процесса, поэтому будет отображаться только весь путь, если пользователь ввел весь путь. Если двоичный файл находится в их PATH, они могут просто ввести foo для его запуска или ./foo, если они находятся в текущем каталоге - argv[0] будет недостаточно в любом случае

Michael Mrozek 17.06.2010 22:28

@Michael Mrozek - это случаи, которые легко обнаружить. Представьте себе логику, которая работает: если argv[0] начинается с '/', рассматривать как абсолютный путь, в противном случае проверьте, содержит ли он '/', если это так, это относительный путь, и вам нужно вставить текущий рабочий каталог, в противном случае вам нужно найти свой двоичный файл в $PATH . Как я уже сказал, это не идеально - я могу называть execve() с argv[0] как "omg ponies", и execve() все равно будет работать.

asveikau 18.06.2010 10:33

если они запускаются с использованием команды с псевдонимом в Linux, является ли argv [0] «именем команды» или расширено?

Andy Dent 04.08.2010 12:16

Решение Windows неправильно проверяет возвращаемое значение (или ожидает, что вызывающий абонент выполнит дополнительную проверку ошибок). Кроме того, он возвращает полный путь к исполняемому файлу. Если вам нужен только каталог (как задается вопросом), вам нужно удалить имя файла с конца пути.

Adrian McCarthy 24.10.2013 22:27

Как насчет добавления char pBuf[256]; size_t len = sizeof(pBuf);, чтобы решение было более четким.

charles.cc.hsu 05.10.2016 16:22

«Спасибо, Майк, ты герой!» теперь гордо присутствует где-то в проекте, над которым я сейчас работаю. Еще я хотел выразить благодарность «лично», так что: спасибо, Майк, ты герой! Ага, сейчас 3:30 утра.

mrDudePerson 20.10.2016 03:29

Вы должны использовать "/proc/self/exe" вместо этой строковой копии mojo. Кроме того, отличный ответ!

Salamandar 11.08.2017 17:20

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

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

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

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

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

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

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

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

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

Пример:

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

Это из 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 );
}

Это решение Windows не будет обрабатывать в пути символы, отличные от ANSI. Вероятно, вам следует использовать GetModuleFileNameW и явно преобразовать его в UTF-8 (будьте осторожны, чтобы преобразовать его обратно, когда вам нужно выполнить команду файловой системы).

Adrian McCarthy 24.10.2013 22:32

Для решения Windows я получаю ошибку error: cannot convert 'char*' to 'LPWCH {aka wchar_t*}' for argument '2' to 'DWORD GetModuleFileNameW(HMODULE, LPWCH, DWORD)' при компиляции с MinGW.

HelloGoodbye 22.01.2014 02:02

@Adrian, я обычно не программист Windows, но разве нет DEFINE или как-то еще, чтобы указать вашему компилятору автоматически использовать вид функций _W ()?

Octopus 08.05.2014 00:41

@Octopus: чтобы использовать широкие вызовы, вам нужно будет использовать WCHAR (вместо char) и std :: wstring (вместо std :: string).

Adrian McCarthy 08.05.2014 02:52

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

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

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

"path/to/file/folder"

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

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

"./path/to/file/folder"

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

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

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

"resources/Example.data"

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

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

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

Да, это работает и в Windows. Я считаю, что это лучшее решение. Насколько мне известно, argv [0] всегда сохраняет путь к исполняемому файлу.

Wodzu 20.10.2016 14:43

argv[0] - очень хорошая идея, но, к сожалению, в Linux я получаю «./my_executable_name» или «./make/my_executable_name». В основном то, что я получаю, полностью зависит от того, как я его запускаю

Xeverous 18.04.2017 13:33

@Xeverous: ну и что? Если у меня есть какие-то файлы, относящиеся к моему исполняемому файлу, которые ему нужно открыть, начиная с «./» или «./make/» в ваших случаях должно работать. "." - это текущий рабочий каталог, а argv [0] сообщит вам относительный путь к исполняемому файлу оттуда, что именно то, что нужно OP. В любом случае это именно то, что мне нужно.

nilo 22.03.2020 22:34

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

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

S. Saad 10.04.2017 02:09

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

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

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

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

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

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

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

Работает с 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
}

Хороший ответ, но добавление деклараций или определений в пространство имен std является неопределенным поведением.. Чтобы избежать этого, вы можете добавить оба пространства имен std::filesystem и std::experimental::filesystem в третье пространство имен по вашему выбору или просто использовать using std::filesystem::path, если вы не возражаете добавить объявление path в глобальное пространство имен.

Cássio Renan 10.06.2019 15:41

Думаю, после C++ 14 экспериментальная :: файловая система больше не используется, так что можно просто забыть об этом? (переходит в первую ветку #if)

TarmoPikaro 10.06.2019 16:50

Всего два цента, но разве следующий код не работает на C++ 17?

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main(int argc, char* argv[])
{
    std::cout << "Path is " << fs::path(argv[0]).parent_path() << '\n';
}

Кажется, у меня работает по крайней мере на Linux.

Основываясь на предыдущей идее, теперь у меня есть:

std::filesystem::path prepend_exe_path(const std::string& filename, const std::string& exe_path = "");

При реализации:

fs::path prepend_exe_path(const std::string& filename, const std::string& exe_path)
{
    static auto exe_parent_path = fs::path(exe_path).parent_path();
    return exe_parent_path / filename;
}

И трюк с инициализацией в main():

(void) prepend_exe_path("", argv[0]);

Спасибо @Sam Redway за идею argv [0]. И, конечно же, я понимаю, что C++ 17 не было много лет, когда ОП задал вопрос.

Путь к текущему .exe


#include <Windows.h>

std::wstring getexepathW()
{
    wchar_t result[MAX_PATH];
    return std::wstring(result, GetModuleFileNameW(NULL, result, MAX_PATH));
}

std::wcout << getexepathW() << std::endl;

//  -------- OR --------

std::string getexepathA()
{
    char result[MAX_PATH];
    return std::string(result, GetModuleFileNameA(NULL, result, MAX_PATH));
}

std::cout << getexepathA() << std::endl;

Это дублирует другой предыдущий ответ и, в отличие от этого, завершится ошибкой в ​​сборках ANSI, потому что неквалифицированный GetModuleFileName преобразуется в GetModuleFileNameA вместо GetModuleFileNameW.

dxiv 28.12.2020 10:46

Я изменил ответ, включив оба варианта. Много любви

The Oathman 28.12.2020 11:21

Другие вопросы по теме