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

Czy istnieje metoda platform-agnostic i filesystem-Agnostic, aby uzyskać pełną ścieżkę katalogu, z którego program jest uruchomiony przy użyciu C / C++? Nie mylić z bieżącym katalogiem roboczym. (Proszę nie sugerować bibliotek, chyba że są one standardowe, takie jak clib lub STL.)

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

 232
Author: casperOne, 2008-09-27

20 answers

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

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;
 155
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-13 16:01:28

Jeśli pobierasz bieżący katalog przy pierwszym uruchomieniu programu, to faktycznie masz katalog, z którego program został uruchomiony. Przechowuj wartość w zmiennej i odwołaj się do niej później w programie. Różni się to od katalogu, w którym znajduje się bieżący plik wykonywalny programu . Niekoniecznie jest to ten sam katalog; jeśli ktoś uruchamia program z wiersza polecenia, to program jest uruchamiany z bieżącego katalogu roboczego wiersza polecenia nawet chociaż plik programu mieszka gdzie indziej.

Getcwd jest funkcją POSIX i jest obsługiwana po wyjęciu z pudełka przez wszystkie platformy zgodne z POSIX. Nie musiałbyś robić nic specjalnego (poza wstawianiem odpowiednich nagłówków unistd.h na Unix i direct.h na windows).

Ponieważ tworzysz program C, połączy się on z domyślną biblioteką czasu uruchamiania c, do której są powiązane wszystkie procesy w systemie (uniknięto specjalnie spreparowanych wyjątków) i domyślnie będzie zawierał tę funkcję. CRT nigdy nie jest uważana za bibliotekę zewnętrzną, ponieważ zapewnia podstawowy interfejs zgodny ze standardem dla systemu operacyjnego.

W systemie Windows Funkcja getcwd została wycofana na rzecz _getcwd. Myślę, że możesz go użyć 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);
 153
Author: computinglife,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:39

To jest z cplusplus forum

W systemie windows:

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

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

Na Linuksie:

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

Na 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 );
}
 30
Author: Octopus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-24 15:59:23

Jeśli chcesz standardową drogę bez bibliotek: Nie. Cała koncepcja katalogu nie jest zawarta w standardzie.

Jeśli zgadzasz się, że niektóre (przenośne) zależności od prawie standardowego lib jest w porządku: Użyj Boost ' S filesystem library i poproś o initial_path () .

IMHO jak najbliżej, z dobrą karmą (Boost to sprawdzony zestaw wysokiej jakości bibliotek)

 28
Author: Thorsten79,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-27 07:23:51

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

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

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

#include <experimental/filesystem>

I połącz swój kod z -lstdc++fs flagą.

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

 17
Author: Marqin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-11 11:38:29

Wiem, że jest bardzo późno, aby rzucić odpowiedź na ten jeden, ale okazało się, że żadna z odpowiedzi nie były tak przydatne dla mnie jak moje własne rozwiązanie. Bardzo prosty sposób na uzyskanie ścieżki z CWD do folderu bin jest następujący:

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 użyć tego jako podstawy dla swojej ścieżki względnej. 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ć log do testowania mogę po prostu dodać ten wiersz do mojego kod.

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

Próbowałem tego podejścia na Linuksie używając pełnej ścieżki, aliasu itp. i działa dobrze.

Uwaga:

Jeśli jesteś w systemie windows, powinieneś użyć ' \ 'jako separatora plików, a nie'/'. Będziesz musiał również uciec od tego na przykład:

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

Myślę, że to powinno działać, ale nie testowałem, więc komentarz byłby mile widziany, jeśli to działa, lub poprawka, jeśli nie.

 15
Author: Sam Redway,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-15 11:30:13

Nie, Nie ma standardowego sposobu. Uważam, że standardy C / C++ nie uwzględniają nawet 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 zostanie ustawiony na NULL. Nie mogę pomóc z Linuksem.

należy również wyjaśnić, czy chcesz bieżący katalog lub katalog, który program image / executable. W obecnej sytuacji Pańskie pytanie jest nieco niejednoznaczne w tej kwestii.

 8
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-27 07:35:51

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

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/pulpit / / test

 7
Author: Jeremy Ruten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-27 07:39:11

Nie można używać argv[0] do tego celu, zazwyczaj zawiera on pełną ścieżkę do pliku wykonywalnego, ale nie jest to możliwe - proces może być utworzony z dowolną wartością w polu.

Pamiętaj również, ż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 Linuksie przeczytaj /dev/proc/procID/.. pliki.

 6
Author: eugensk00,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-13 04:12:24

Dla Win32 GetCurrentDirectory powinno wystarczyć.

 5
Author: Torbjörn Gyllebring,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-27 07:21:01

Dla systemu Windows w konsoli można użyć polecenia system(dir). A konsola daje informacje o katalogu itp. Przeczytaj o komendzie dir w cmd. Ale dla systemów uniksopodobnych, Nie wiem... Jeśli to polecenie jest uruchomione, przeczytaj polecenie bash. ls nie wyświetla katalogu...

Przykład:

int main()
{
    system("dir");
    system("pause"); //this wait for Enter-key-press;
    return 0;
}
 4
Author: Alexey1993,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-10 17:13:27

Tylko po to, by z opóźnieniem ułożyć tutaj,...

Nie ma standardowego rozwiązania, ponieważ języki te są niezależne od bazowych systemów plików, więc jak mówili inni, pojęcie systemu plików opartego na katalogach jest poza zakresem języków c / C++.

Poza tym, nie chcesz bieżącego katalogu roboczego, ale katalogu, w którym działa program, który musi wziąć pod uwagę, jak program dotarł do miejsca, w którym się znajduje - tj. czy powstał jako nowy proces przez fork, itp. Aby uzyskać katalog, w którym uruchomiony jest program, jak wykazały rozwiązania, należy uzyskać te informacje ze struktur sterowania procesami danego systemu operacyjnego, który jest jedynym organem w tej kwestii. Tak więc, z definicji, jest to rozwiązanie specyficzne dla systemu operacyjnego.

 3
Author: Minok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-27 23:50:14

W systemie Windows najprostszym sposobem jest użycie funkcji _get_pgmptr w stdlib.h, aby uzyskać wskaźnik do ciągu znaków, który reprezentuje absolutną ścieżkę do pliku wykonywalnego, w tym nazwę pliku wykonywalnego.

char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe
 3
Author: Adam Yaxley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-10 07:52:44
#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
Author: freezotic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-19 17:20:58

Polecenie linux bash który progname zgłosi ścieżkę do programu.

Nawet jeśli można wydać polecenie which z programu i skierować wyjście do pliku tmp i programu następnie odczytuje ten plik tmp, nie powie Ci, czy ten program jest wykonywany. Informuje tylko, gdzie znajduje się program o tej nazwie.

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

In my program chcę wiedzieć czy program był wykonywane z katalogu bin użytkownika lub z innego w ścieżce lub z /usr / bin. /usr / bin będzie zawierał obsługiwaną wersję. Mam wrażenie, że w Linuksie jest jedyne rozwiązanie, które jest przenośne.

 1
Author: Leslie Satenstein,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-22 15:46:54

Dla ścieżek względnych, oto co zrobiłem. Jestem świadomy wieku tego pytania, po prostu chcę wnieść prostszą odpowiedź, 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 na Linuksie wykonane w eclipse dobrze z tym współpracują. Jednak System windows jest bardzo zdezorientowany, jeśli podano taką ścieżkę do pracy!

Jak wspomniano powyżej istnieje kilka sposobów, aby uzyskać bieżącą ścieżkę do pliku wykonywalnego, ale najprostszym sposobem I find works urokiem w większości przypadków jest dołączenie tego do przodu swojej ścieżki:

"./path/to/file/folder"

Tylko dodaję "./ align = "left" / :) Wtedy możesz rozpocząć ładowanie z dowolnego katalogu, o ile jest to z samym programem wykonywalnym.

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

EDIT2: kilka nowych rzeczy, które mam okazało się, że jeśli podasz statyczną ścieżkę, taką jak ta w kodzie (zakładając przykład.dane trzeba załadować):
"resources/Example.data"

Jeśli następnie uruchomić aplikację z rzeczywistego katalogu (lub w systemie Windows, można utworzyć skrót, i ustawić katalog roboczy do katalogu aplikacji) to będzie działać w ten sposób. Należy o tym pamiętać podczas debugowania problemów związanych z brakującymi ścieżkami zasobów/plików. (Szczególnie w Idach, które ustawiają źle działający katalog podczas uruchamiania build exe z IDE)

 1
Author: FuzzyQuills,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-02 01:34:04

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

W systemie Windows możesz użyć _getcwd(), ponieważ użycie getcwd() zostało przestarzałe.

W przypadku bibliotek standardowych, gdyby Boost był wystarczająco standardowy dla Ciebie, zasugerowałbym Boost::filesystem, ale wydaje się, że usunęły normalizację ścieżek z propozycji. Być może będziesz musiał poczekać, aż TR2 stanie się łatwo dostępne na w pełni standardowe rozwiązanie.

 0
Author: Fruny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-27 07:31:38

Boost Filesystem initial_path() zachowuje się jak POSIX getcwd() i nie robi tego, co chcesz, ale dołączenie argv[0] do jednego z nich powinno to zrobić.

Możesz zauważyć, że wynik nie zawsze jest ładny-możesz uzyskać rzeczy takie jak /foo/bar/../../baz/a.out lub /foo/bar//baz/a.out, ale wierzę, że zawsze powoduje to poprawną ścieżkę, która nazywa program wykonywalny(zauważ, że kolejne ukośniki w ścieżce są zwinięte do jednego).

Napisałem wcześniej rozwiązanie używając envp (trzeciego argumentu do main(), które działało na Linux, ale nie wydaje się działać na Windows, więc w zasadzie polecam to samo rozwiązanie, co ktoś inny zrobił wcześniej, ale z dodatkowym wyjaśnieniem, dlaczego jest to rzeczywiście poprawne, nawet jeśli wyniki nie są ładne.

 0
Author: John Zwinck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-24 01:24:59

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

Thorsten79 napisał (a):Biblioteka systemu plików. Jednakże, może to być niewygodne w przypadku, gdy nie chcesz mieć żadnych zależności od czasu łącza w postaci binarnej dla Twojego programu.

Dobrą alternatywą polecam jest zbiór 100% tylko nagłówki Biblioteki STLSoft C++ Matthew Wilson (autor obowiązkowych książek o C++). Jest przenośne 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ślone za pomocą cech i zasad, więc jest to rozszerzalny framework. Oczywiście dostępna jest biblioteka systemu plików.

 0
Author: mloskot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-28 00:26:18

Rozwiązanie biblioteczne (choć wiem, że o to nie proszono). W przypadku stosowania Qt: QCoreApplication::applicationDirPath()

 -1
Author: Joachim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-04 09:38:03