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.)
c++
c
working-directory
Ashwin Nanjappa
źródło
źródło
argv[0]
, technika będzie bardzo zależna od systemu operacyjnego.#include <windows.h>
, Windows automatycznie umieszcza achar*
na ścieżce do pliku wykonywalnego_pgmptr
. Nie musisz wywoływać dodatkowych funkcji ani zakładać śmieci, jeśli pracujesz tylko w systemie Windows._pgmptr
. Dokumentacja MSDN stwierdza, że zmienne_pgmptr
i_wpgmptr
są przestarzałe i należy użyć funkcji_get_pgmptr(char**)
lub_get_wpgmptr(wchar_t**)
zamiast niej. MSDNOdpowiedzi:
Oto kod, aby uzyskać pełną ścieżkę do uruchomionej aplikacji:
Windows:
Linux:
źródło
/proc
część mnie, umiera trochę. Cały świat nie jest Linuksem i nawet na tej jednej platformie/proc
należy rozważyć zmianę z wersji na wersję, od arch do arch itp.char pBuf[256]; size_t len = sizeof(pBuf);
aby rozwiązanie było wyraźniejsze.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.
źródło
To jest z forum cplusplus
W systemie Windows:
W systemie Linux:
W systemie HP-UX:
źródło
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.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)
źródło
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:W gcc (5.3+), aby dołączyć system plików, musisz użyć:
i połącz swój kod z
-lstdc++fs
flagą.Jeśli chcesz używać systemu plików z Microsoft Visual Studio, przeczytaj to .
źródło
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.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:
Możesz teraz po prostu użyć tego jako podstawy dla swojej względnej ścieżki. Na przykład mam taką strukturę katalogów:
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.
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:
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.
źródło
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ę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.źródło
W systemie Windows najprostszym sposobem jest użycie
_get_pgmptr
funkcji in,stdlib.h
aby uzyskać wskaźnik do łańcucha, który reprezentuje bezwzględną ścieżkę do pliku wykonywalnego, w tym nazwę pliku wykonywalnego.źródło
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:
Po uruchomieniu wyświetla:
źródło
W przypadku Win32 GetCurrentDirectory powinien załatwić sprawę.
źródło
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 / ...
źródło
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.
źródło
W przypadku systemu Windows na konsoli można użyć
dir
polecenia system ( ). Konsola zawiera informacje o katalogu itp. Przeczytaj odir
poleceniu nacmd
. Ale w systemach uniksowych nie wiem ... Jeśli to polecenie zostanie uruchomione, przeczytaj polecenie bash.ls
nie wyświetla katalogu ...Przykład:
źródło
źródło
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.
źródło
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ę:
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:
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ć):
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)
źródło
Rozwiązanie biblioteczne (choć wiem, że nie został o to poproszony). Jeśli zdarzy ci się użyć Qt:
QCoreApplication::applicationDirPath()
źródło
Tylko moje dwa centy, ale czy poniższy kod nie działa przenośnie w C ++ 17?
Wydaje się, że działa dla mnie przynajmniej na Linuksie.
W oparciu o poprzedni pomysł mam teraz:
Z wdrożeniem:
I sztuczka inicjalizacji w
main()
:Dzięki @Sam Redway za pomysł argv [0]. I oczywiście rozumiem, że C ++ 17 nie istniał przez wiele lat, kiedy OP zadał pytanie.
źródło
Boost Fileystem
initial_path()
zachowuje się jak POSIXgetcwd()
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.out
lub/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.źródło
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.
źródło
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.
źródło
Użyj
realpath()
wstdlib.h
następujący sposób:źródło
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:
application.cpp:
źródło
std
. Aby tego uniknąć, możesz dodać zarówno przestrzenie nazw, jakstd::filesystem
istd::experimental::filesystem
trzecią wybraną przestrzeń nazw, lub po prostu użyćusing std::filesystem::path
, jeśli nie masz nic przeciwko dodaniu deklaracjipath
do globalnej przestrzeni nazw.