Jak uzyskać katalog, z którego działa program?

269

Czy istnieje metoda niezależna od platformy i metoda niezależna od systemu plików, aby uzyskać pełną ścieżkę do katalogu, w którym program działa przy użyciu C / C ++? Nie mylić z bieżącym katalogiem roboczym. (Proszę nie sugerować bibliotek, chyba że są to standardowe biblioteki, takie jak clib lub STL.)

(Jeśli nie ma metody niezależnej od platformy / systemu plików, mile widziane są również sugestie, które działają w systemach Windows i Linux dla określonych systemów plików.)

Ashwin Nanjappa
źródło
@chakrit: Byłoby świetnie. (Chociaż ten problem zwykle nie pojawia się w systemie Windows.)
Ashwin Nanjappa
2
O ile nie można wiarygodnie wyodrębnić ścieżki argv[0], technika będzie bardzo zależna od systemu operacyjnego.
David R Tribble
1
Dla wyjaśnienia: „bieżący katalog” lub „katalog, z którego program działa” (w terminologii pytania) to katalog, w którym znajduje się plik obrazu programu (plik ~ .exe), oraz „bieżący katalog roboczy ” to katalog, który jest autouzupełniany, jeśli program używa ścieżek względnych?
colemik
3
Kiedy ty #include <windows.h>, Windows automatycznie umieszcza a char*na ścieżce do pliku wykonywalnego _pgmptr. Nie musisz wywoływać dodatkowych funkcji ani zakładać śmieci, jeśli pracujesz tylko w systemie Windows.
rsethc
1
Chociaż komentarz pochodzi z trzech lat temu, chciałbym rozwinąć komentarz na temat rsethc _pgmptr. Dokumentacja MSDN stwierdza, że zmienne _pgmptri _wpgmptrsą przestarzałe i należy użyć funkcji _get_pgmptr(char**)lub _get_wpgmptr(wchar_t**)zamiast niej. MSDN
Hydranix,

Odpowiedzi:

181

Oto kod, aby uzyskać pełną ścieżkę do uruchomionej aplikacji:

Windows:

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;
Deduplikator
źródło
3
Myślę, że to jedyna odpowiedź tutaj, która odpowiada na pytanie, i robi to zarówno w przypadku systemu Windows, jak i Linux. Dobra robota.
Frank Szczerba
6
Boo dla / proc / pid / exe - Z jakiegoś powodu nie jest obsługiwany w OS X.
Chris Lutz
24
Kiedy widzę kod, który patrzy na /procczęść mnie, umiera trochę. Cały świat nie jest Linuksem i nawet na tej jednej platformie /procnależy rozważyć zmianę z wersji na wersję, od arch do arch itp.
asveikau
4
jeśli uruchamiają przy użyciu aliasu polecenia w systemie Linux, czy argv [0] jest „nazwą polecenia”, czy jest rozwinięty?
Andy Dent
20
Co powiesz na dodanie, char pBuf[256]; size_t len = sizeof(pBuf);aby rozwiązanie było wyraźniejsze.
charles.cc.hsu
166

Jeśli pobierzesz bieżący katalog przy pierwszym uruchomieniu programu, to faktycznie masz katalog, z którego program został uruchomiony. Zapisz wartość w zmiennej i odwołaj się do niej później w swoim programie. Różni się to od katalogu, w którym znajduje się bieżący plik programu wykonywalnego . To niekoniecznie ten sam katalog; jeśli ktoś uruchomi program z wiersza polecenia, wówczas program jest uruchamiany z bieżącego katalogu roboczego wiersza polecenia, mimo że plik programu znajduje się gdzie indziej.

getcwd jest funkcją POSIX i jest obsługiwany od razu przez wszystkie platformy zgodne z POSIX. Nie musisz robić nic specjalnego (oprócz włączenia odpowiednich nagłówków unistd.h na Unixie i direct.h na Windowsie).

Ponieważ tworzysz program C, połączy się on z domyślną biblioteką czasu wykonywania c, do której prowadzą WSZYSTKIE procesy w systemie (unikając specjalnie spreparowanych wyjątków) i domyślnie będzie zawierał tę funkcję. CRT nigdy nie jest uważany za bibliotekę zewnętrzną, ponieważ zapewnia podstawowy standardowy interfejs zgodny z systemem operacyjnym.

W systemie Windows funkcja getcwd jest przestarzała na rzecz _getcwd. Myślę, że możesz użyć tego w ten sposób.

#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);
życie komputerowe
źródło
44
Dobra odpowiedź, ale myślałem, że „bieżący katalog roboczy” nie był tym, czego chciałem.
Michael Burr
4
powinieneś dodać, że nawet jeśli niektóre dokumenty mówią, że cCurrentpath może mieć wartość null i zostanie przydzielone przez getcwd, getcwd nie wydaje się przydzielać czegoś w systemie Mac OS i po cichu powoduje awarię programu
Janusz
4
Jest mały błąd, ale niestety nie mogę jeszcze edytować .. wiersz 10: cCurrentpath: powinien być cCurrentPath
Lipis
8
IMO w systemie Windows należy zasadniczo unikać funkcji o nazwie POSIXy (niektóre z nich zaczynające się od podkreślników). Nie są to prawdziwe interfejsy API systemu Windows, ale raczej CRT. Interfejs API systemu Windows, którego chcesz użyć, to GetCurrentDirectory (). msdn.microsoft.com/en-us/library/aa364934(VS.85).aspx
asveikau
6
Odpowiedź Mike'a jest poprawna. „Bieżący katalog” nie zawsze jest taki sam jak katalog, z którego uruchomiony jest plik binarny. Na przykład, jeśli aplikacja działa jako usługa w systemie Windows, bieżącym katalogiem będzie prawdopodobnie C: \ Windows \ System32, podczas gdy katalog binarny jest inny.
Lucky Luke
42

To jest z forum cplusplus

W systemie Windows:

#include <string>
#include <windows.h>

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

W systemie 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 );
}

W systemie 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 );
}
Ośmiornica
źródło
1
To rozwiązanie systemu Windows nie obsługuje ścieżek innych niż ANSI. Prawdopodobnie powinieneś użyć GetModuleFileNameW i jawnie przekonwertować go na UTF-8 (uważaj, aby przekonwertować go z powrotem za każdym razem, gdy musisz wydać polecenie systemu plików).
Adrian McCarthy
3
W przypadku rozwiązania Windows error: cannot convert 'char*' to 'LPWCH {aka wchar_t*}' for argument '2' to 'DWORD GetModuleFileNameW(HMODULE, LPWCH, DWORD)'pojawia się błąd podczas kompilacji z MinGW.
HelloGoodbye
2
@Adrian, na ogół nie jestem programistą systemu Windows, ale czy nie ma DEFINICJI, ani nie ma w ogóle polecenia kompilatorowi do automatycznego korzystania z funkcji _W () funkcji?
Ośmiornica
1
@Octopus: Aby użyć szerokich wywołań, musisz użyć WCHAR (zamiast char) i std :: wstring (zamiast std :: string).
Adrian McCarthy
29

Jeśli chcesz standardowego sposobu bez bibliotek: Nie. Cała koncepcja katalogu nie jest uwzględniona w standardzie.

Jeśli zgadzasz się, że niektóre (przenośne) zależności od prawie standardowej biblioteki lib są w porządku: Skorzystaj z biblioteki systemu plików Boost i poproś o initial_path () .

IMHO jest tak blisko, jak to tylko możliwe, z dobrą karmą (Boost to dobrze znany zestaw bibliotek wysokiej jakości)

Thorsten79
źródło
8
Z dokumentacji wspomagającej: template <class Path> const Path & initial_path (); Zwraca: current_path () w momencie wejścia do main (). A current_path () to „jakby POSIX getcwd ()”. Nie tego wymagał pytający.
Jonathan Leffler
Jak skomentowano, daje to ścieżkę, z której wywołano plik binarny, a nie ścieżkę do pliku binarnego ... ponieważ można go uruchomić z innego folderu.
jpo38
21

System plików TS jest teraz standardem (i jest obsługiwany przez gcc 5.3+ i clang 3.9+), więc możesz używać current_path()z niego funkcji:

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

W gcc (5.3+), aby dołączyć system plików, musisz użyć:

#include <experimental/filesystem>

i połącz swój kod z -lstdc++fsflagą.

Jeśli chcesz używać systemu plików z Microsoft Visual Studio, przeczytaj to .

Marqin
źródło
6
Z 1-2) Returns the absolute path of the current working directory, obtained as if by POSIX getcwd. (2) returns path() if error occurs. odsyłającego linku, Downvoted, ponieważ OP konkretnie pyta o bieżącą ścieżkę pliku wykonywalnego, a nie o bieżący katalog roboczy.
S. Saad,
20

Wiem, że jest już bardzo późno, aby odpowiedzieć na to pytanie, ale stwierdziłem, że żadna z odpowiedzi nie była dla mnie tak przydatna jak moje własne rozwiązanie. Bardzo prosty sposób na uzyskanie ścieżki z CWD do folderu bin wygląda następująco:

int main(int argc, char* argv[])
{
    std::string argv_str(argv[0]);
    std::string base = argv_str.substr(0, argv_str.find_last_of("/"));
}

Możesz teraz po prostu użyć tego jako podstawy dla swojej względnej ścieżki. Na przykład mam taką strukturę katalogów:

main
  ----> test
  ----> src
  ----> bin

i chcę skompilować mój kod źródłowy do bin i napisać dziennik do przetestowania. Mogę po prostu dodać tę linię do mojego kodu.

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

Wypróbowałem to podejście w systemie Linux, używając pełnej ścieżki, aliasu itp. I działa dobrze.

UWAGA:

Jeśli korzystasz z systemu Windows, powinieneś użyć „\” jako separatora plików, a nie „/”. Trzeba będzie też uciec przed tym:

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

Myślę, że to powinno działać, ale nie zostało przetestowane, więc komentarz będzie mile widziany, jeśli zadziała, lub poprawka, jeśli nie.

Sam Redway
źródło
Tak, działa również w systemie Windows. Myślę, że to najlepsze rozwiązanie. O ile wiem argv [0] zawsze utrzymuje ścieżkę do pliku wykonywalnego.
Wodzu,
4
argv[0]to bardzo fajny pomysł, ale niestety to, co otrzymuję w systemie Linux, to „./my_executable_name” lub „./make/my_executable_name”. Zasadniczo to, co dostaję, zależy całkowicie od tego, jak go uruchomię
Xeverous
@ Xeverous: co z tego? Jeśli mam jakieś pliki w stosunku do mojego pliku wykonywalnego, które musi on otworzyć, zaczynając od „./” lub „./make/” w twoim przypadku powinno działać. „.” jest bieżącym katalogiem roboczym, a argv [0] poda ci stamtąd względną ścieżkę do pliku wykonywalnego, czego dokładnie potrzebuje OP. W każdym razie dokładnie tego potrzebuję.
nilo
9

Nie, nie ma standardowego sposobu. Uważam, że standardy C / C ++ nawet nie uwzględniają istnienia katalogów (lub innych organizacji systemów plików).

W systemie Windows funkcja GetModuleFileName () zwróci pełną ścieżkę do pliku wykonywalnego bieżącego procesu, gdy parametr hModule ma wartość NULL . Nie mogę pomóc z Linuksem.

Powinieneś także wyjaśnić, czy chcesz mieć bieżący katalog, czy katalog, w którym znajduje się obraz programu / plik wykonywalny. W tej chwili twoje pytanie jest trochę niejednoznaczne w tej kwestii.

Michael Burr
źródło
9

W systemie Windows najprostszym sposobem jest użycie _get_pgmptrfunkcji in, stdlib.haby uzyskać wskaźnik do łańcucha, który reprezentuje bezwzględną ścieżkę do pliku wykonywalnego, w tym nazwę pliku wykonywalnego.

char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe
Adam Yaxley
źródło
8

Może połączyć bieżący katalog roboczy z argv [0]? Nie jestem pewien, czy to zadziała w systemie Windows, ale działa w systemie Linux.

Na przykład:

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

Po uruchomieniu wyświetla:

jeremy @ jeremy-desktop: ~ / Desktop $ ./test
/home/jeremy/Desktop/./test

Jeremy Ruten
źródło
Musisz sprawdzić, czy w argv podano ścieżkę bezwzględną [0]. Ale co ważniejsze, co jeśli obraz znajduje się za pośrednictwem ŚCIEŻKI? Czy linux wypełnia pełną ścieżkę, czy tylko to, co jest w wierszu poleceń?
Michael Burr
Jak zauważył Mike B, jest to rozwiązanie nie ogólne; działa tylko w niektórych bardzo ograniczonych okolicznościach. Zasadniczo tylko wtedy, gdy uruchamiasz polecenie za pomocą względnej nazwy ścieżki - i nie jest aż tak elegancko, gdy uruchamiasz ../../../bin/progname zamiast ./test
Jonathan Leffler
Jeśli rozwiążesz możliwą ścieżkę względną argv [0] w porównaniu z bieżącym katalogiem (ponieważ argv [0] może być „../../myprogram.exe”), jest to prawdopodobnie najbezpieczniejszy sposób odpowiedzi na pytanie. Zawsze będzie działać i jest przenośny (działa nawet na Androidzie!).
jpo38
7

W przypadku Win32 GetCurrentDirectory powinien załatwić sprawę.

Torbjörn Gyllebring
źródło
Ta funkcja ma duże znaczenie : aplikacje wielowątkowe i kod biblioteki współdzielonej nie powinny korzystać z funkcji GetCurrentDirectory i powinny unikać używania względnych ścieżek . Jeśli możesz pracować z tym założeniem, jest to najlepsze rozwiązanie.
McLeary
6

W tym celu nie można użyć argumentu argv [0], zwykle zawiera on pełną ścieżkę do pliku wykonywalnego, ale nie jest to konieczne - proces można utworzyć z dowolną wartością w polu.

Pamiętaj też, że bieżący katalog i katalog z plikiem wykonywalnym to dwie różne rzeczy, więc getcwd () też ci nie pomoże.

W systemie Windows użyj GetModuleFileName (), w systemie Linux pliki do odczytu / dev / proc / procID / ...

Eugeniusz
źródło
3

Aby spóźnić się tutaj, ...

nie ma standardowego rozwiązania, ponieważ języki są agnostyczne dla bazowych systemów plików, tak jak inni powiedzieli, koncepcja systemu plików opartego na katalogu jest poza zakresem języków c / c ++.

na dodatek nie chcesz mieć bieżącego katalogu roboczego, ale katalog, w którym działa program, który musi wziąć pod uwagę, w jaki sposób program dotarł do miejsca, w którym się znajduje - tj. czy został odrodzony jako nowy proces przez rozwidlenie itp. Aby uzyskać katalog, w którym działa program, jak wykazały rozwiązania, wymagane jest uzyskanie tych informacji ze struktur kontroli procesu w danym systemie operacyjnym, który jest jedynym autorytetem w tym pytaniu. Dlatego z definicji jest to rozwiązanie specyficzne dla systemu operacyjnego.

Minok
źródło
3

W przypadku systemu Windows na konsoli można użyć dirpolecenia system ( ). Konsola zawiera informacje o katalogu itp. Przeczytaj o dirpoleceniu na cmd. Ale w systemach uniksowych nie wiem ... Jeśli to polecenie zostanie uruchomione, przeczytaj polecenie bash. lsnie wyświetla katalogu ...

Przykład:

int main()
{
    system("dir");
    system("pause"); //this wait for Enter-key-press;
    return 0;
}
Alexey1993
źródło
2
#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);
}
zamrażający
źródło
1

Na platformach POSIX można użyć getcwd () .

W systemie Windows możesz użyć _getcwd () , podobnie jak getcwd () jest przestarzałe.

W przypadku bibliotek standardowych, gdyby Boost był wystarczająco standardowy, sugerowałbym Boost :: system plików, ale wydaje się, że usunęły one normalizację ścieżki z propozycji. Być może będziesz musiał poczekać, aż TR2 stanie się łatwo dostępny dla w pełni standardowego rozwiązania.

Owocowy
źródło
10
getcwd () nie robi tego, o co pytał pytający.
Jonathan Leffler
czy nie jest tak, że zaakceptowana odpowiedź używa getcwd (), czy też nie rozumiem?
Sнаđошƒаӽ
Głosowałem za tym, ponieważ jesteś tym, który jako pierwszy przyszedł z właściwą odpowiedzią.
Arnaud
Ta odpowiedź nawet nie próbuje odpowiedzieć na pytanie. Wstyd, pisząc to.
HelloWorld,
1

Dla względnych ścieżek, oto co zrobiłem. Zdaję sobie sprawę z wieku tego pytania, chcę po prostu udzielić prostszej odpowiedzi, która działa w większości przypadków:

Powiedz, że masz taką ścieżkę:

"path/to/file/folder"

Z jakiegoś powodu pliki wykonywalne zbudowane w systemie Linux wykonane w środowisku Eclipse działają z tym dobrze. Jednak Windows staje się bardzo zdezorientowany, jeśli ma taką ścieżkę do pracy!

Jak wspomniano powyżej, istnieje kilka sposobów, aby uzyskać bieżącą ścieżkę do pliku wykonywalnego, ale najłatwiejszy sposób, jaki uważam, działa za urok w większości przypadków, dodając to do PRZEDNIEJ ścieżki:

"./path/to/file/folder"

Dodanie „./” powinno posortować! :) Następnie możesz rozpocząć ładowanie z dowolnego katalogu, o ile chcesz z samego pliku wykonywalnego.

EDYCJA: To nie zadziała, jeśli spróbujesz uruchomić plik wykonywalny z kodu :: blocks, jeśli jest to używane środowisko programistyczne, ponieważ z jakiegoś powodu kod :: bloki nie ładuje się poprawnie ...: D

EDIT2: Kilka nowych rzeczy, które znalazłem, to to, że jeśli podasz ścieżkę statyczną, taką jak ta w swoim kodzie (Zakładając, że przykład.data jest czymś, co musisz załadować):

"resources/Example.data"

Jeśli następnie uruchomisz aplikację z rzeczywistego katalogu (lub w systemie Windows utworzysz skrót i ustawisz katalog roboczy na katalog aplikacji), to tak będzie działać. Należy o tym pamiętać podczas debugowania problemów związanych z brakującymi ścieżkami zasobów / plików. (Szczególnie w IDE, które ustawiają zły katalog roboczy podczas uruchamiania exe kompilacji z IDE)

FuzzyQuills
źródło
1

Rozwiązanie biblioteczne (choć wiem, że nie został o to poproszony). Jeśli zdarzy ci się użyć Qt: QCoreApplication::applicationDirPath()

Joachim
źródło
1

Tylko moje dwa centy, ale czy poniższy kod nie działa przenośnie w 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';
}

Wydaje się, że działa dla mnie przynajmniej na Linuksie.

W oparciu o poprzedni pomysł mam teraz:

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

Z wdrożeniem:

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

I sztuczka inicjalizacji w main():

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

Dzięki @Sam Redway za pomysł argv [0]. I oczywiście rozumiem, że C ++ 17 nie istniał przez wiele lat, kiedy OP zadał pytanie.

nilo
źródło
0

Boost Fileystem initial_path()zachowuje się jak POSIX getcwd()i nie robi tego, co chcesz sam, ale dołączaargv[0] do któregokolwiek z nich powinno to zrobić.

Możesz zauważyć, że wynik nie zawsze jest ładny - możesz dostać takie rzeczy jak /foo/bar/../../baz/a.outlub/foo/bar//baz/a.out , ale uważam, że zawsze skutkuje to prawidłową ścieżką, która określa nazwę pliku wykonywalnego (zwróć uwagę, że kolejne ukośniki na ścieżce są zwinięte do jednej).

Wcześniej napisałem rozwiązanie przy użyciu envp(trzeci argument, main()który działał w systemie Linux, ale nie wydawał się praktyczny w systemie Windows, więc zasadniczo zalecam to samo rozwiązanie, co wcześniej ktoś inny, ale z dodatkowym wyjaśnieniem, dlaczego tak naprawdę jest poprawne nawet jeśli wyniki nie są ładne.

John Zwinck
źródło
0

Jak wspomniał Minok , nie ma takiej funkcjonalności określonej w standardzie C lub C ++. Jest to uważane za funkcję specyficzną dla systemu operacyjnego i na przykład jest określone w standardzie POSIX.

Thorsten79 dał dobrą sugestię, jest to biblioteka Boost.Filesystem. Może to być jednak niewygodne w przypadku, gdy nie chcesz mieć żadnych zależności łącza w czasie w postaci binarnej dla swojego programu.

Dobrą alternatywą, którą poleciłbym, jest zbiór 100% tylko bibliotek nagłówków STLSoft C ++ Matthew Wilson (autor książek, które należy przeczytać o C ++). Istnieje przenośna fasada PlatformSTL daje dostęp do specyficznego dla systemu API: WinSTL dla Windows i UnixSTL na Unix, więc jest to rozwiązanie przenośne. Wszystkie elementy specyficzne dla systemu są określane za pomocą cech i zasad, więc jest to rozszerzalna struktura. Oczywiście dostępna jest biblioteka systemu plików.

mloskot
źródło
0

Polecenie linuksowe, które prognozuje , zgłosi ścieżkę do programu.

Nawet jeśli ktoś wyda polecenie które z twojego programu i przekieruje wyjście do pliku tmp, a następnie program odczyta ten plik tmp, nie powie ci, czy ten program jest tym, który wykonuje. Mówi tylko, gdzie znajduje się program o tej nazwie.

Wymagane jest uzyskanie numeru identyfikacyjnego procesu i przeanalizowanie ścieżki do nazwy

W moim programie chcę wiedzieć, czy program został wykonany z katalogu bin użytkownika, czy z innego w ścieżce lub z / usr / bin. / usr / bin zawierałby obsługiwaną wersję. Mam wrażenie, że w Linuksie jest jedno rozwiązanie, które jest przenośne.

Leslie Satenstein
źródło
0

Użyj realpath()w stdlib.hnastępujący sposób:

char *working_dir_path = realpath(".", NULL);
Manabu Nakazawa
źródło
0

Działa z wersją C ++ 11, przy użyciu eksperymentalnego systemu plików i C ++ 14-C ++ 17, a także przy użyciu oficjalnego systemu plików.

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
}
TarmoPikaro
źródło
Dobra odpowiedź, ale dodawanie deklaracji lub definicji do przestrzeni nazw jest niezdefiniowanym zachowaniemstd . Aby tego uniknąć, możesz dodać zarówno przestrzenie nazw, jak std::filesystemi std::experimental::filesystemtrzecią wybraną przestrzeń nazw, lub po prostu użyć using std::filesystem::path, jeśli nie masz nic przeciwko dodaniu deklaracji pathdo globalnej przestrzeni nazw.
Cássio Renan,
Chyba po eksperymentalnym systemie plików C ++ 14 nie jest już używany, więc możesz o tym zapomnieć? (wchodzi do pierwszego oddziału
#if