Domanda

Esiste un metodo indipendente dalla piattaforma e indipendente dal filesystem per ottenere il percorso completo della directory da cui è in esecuzione un programma usando C / C ++? Da non confondere con la directory di lavoro corrente. (Ti preghiamo di non suggerire librerie a meno che non siano standard come clib o STL.)

(Se non esiste un metodo indipendente dalla piattaforma / filesystem, anche i suggerimenti che funzionano in Windows e Linux per filesystem specifici sono i benvenuti.)

È stato utile?

Soluzione

Ecco il codice per ottenere il percorso completo dell'app in esecuzione:

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;

Altri suggerimenti

Se recuperi la directory corrente al primo avvio del programma, hai effettivamente la directory da cui è stato avviato il programma. Memorizza il valore in una variabile e fai riferimento ad esso più avanti nel tuo programma. Ciò è distinto da la directory che contiene il file di programma eseguibile corrente . Non è necessariamente la stessa directory; se qualcuno esegue il programma da un prompt dei comandi, allora il programma viene eseguito da l'attuale directory di lavoro del prompt dei comandi anche se il file di programma risiede altrove.

getcwd è una funzione POSIX e supportata da tutte le piattaforme compatibili con POSIX. Non dovresti fare nulla di speciale (a parte l'inclusione delle intestazioni giuste unistd.h su Unix e direct.h su windows).

Poiché si sta creando un programma C, esso si collegherà alla libreria di runtime c predefinita a cui sono collegati TUTTI i processi nel sistema (evitate eccezioni appositamente predisposte) e includerà questa funzione per impostazione predefinita. Il CRT non è mai considerato una libreria esterna perché fornisce al sistema operativo l'interfaccia conforme allo standard di base.

Su Windows la funzione getcwd è stata deprecata a favore di _getcwd. Penso che potresti usarlo in questo modo.

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

Questo è dal forum cplusplus

Su Windows:

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

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

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

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

Se vuoi un modo standard senza librerie: No. L'intero concetto di directory non è incluso nello standard.

Se sei d'accordo che una dipendenza (portatile) da una lib quasi standard va bene: usa libreria del filesystem di Boost e chiedi la initial_path () .

IMHO il più vicino possibile, con un buon karma (Boost è un set di librerie di alta qualità ben consolidato)

TS filesystem è ora uno standard (e supportato da gcc 5.3 + e clang 3.9+), così puoi usare current_path () da esso:

In gcc (5.3+) per includere il filesystem devi usare:

#include <experimental/filesystem>

e collega il tuo codice con -lstdc ++ fs flag.

Se vuoi usare il filesystem con Microsoft Visual Studio, allora leggi questo .

So che è molto tardi per dare una risposta a questo, ma ho scoperto che nessuna delle risposte mi è stata utile come la mia soluzione. Un modo molto semplice per ottenere il percorso dal CWD alla cartella bin è in questo modo:

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

Ora puoi semplicemente usarlo come base per il tuo percorso relativo. Quindi ad esempio ho questa struttura di directory:

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

e voglio compilare il mio codice sorgente nel cestino e scrivere un registro per testare, posso solo aggiungere questa riga al mio codice.

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

Ho provato questo approccio su Linux usando il percorso completo, alias ecc. e funziona perfettamente.

NOTA:

Se sei su Windows dovresti usare un '\' come separatore di file non '/'. Dovrai scappare anche da questo, ad esempio:

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

Penso che questo dovrebbe funzionare ma non è stato testato, quindi sarebbe gradito un commento se funziona o una soluzione se no.

No, non esiste un modo standard. Credo che gli standard C / C ++ non considerino nemmeno l'esistenza di directory (o altre organizzazioni di file system).

Su Windows GetModuleFileName () restituirà il percorso completo al file eseguibile del processo corrente quando il parametro hModule è impostato su NULL . Non posso fare a meno di Linux.

Inoltre è necessario chiarire se si desidera la directory corrente o la directory in cui risiede l'immagine del programma / eseguibile. Allo stato attuale, la tua domanda è un po 'ambigua su questo punto.

Forse concatenare l'attuale directory di lavoro con argv [0]? Non sono sicuro che funzionerebbe in Windows ma funziona in Linux.

Ad esempio:

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

Quando eseguito, genera:

  

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

Non è possibile utilizzare argv [0] a tale scopo, di solito contiene il percorso completo dell'eseguibile, ma non necessariamente - il processo potrebbe essere creato con valore arbitrario nel campo.

Inoltre, la directory corrente e la directory con l'eseguibile sono due cose diverse, quindi getcwd () non ti aiuterà neanche.

Su Windows usa GetModuleFileName (), su Linux leggi / dev / proc / procID / .. file.

Su Windows il modo più semplice è utilizzare la funzione _get_pgmptr in stdlib.h per ottenere un puntatore a una stringa che rappresenta il percorso assoluto dell'eseguibile, incluso il nome degli eseguibili.

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

Per Win32 GetCurrentDirectory dovrebbe fare il trucco .

Solo per accumulare in ritardo qui, ...

non esiste una soluzione standard, poiché le lingue sono agnostiche rispetto ai file system sottostanti, quindi, come altri hanno già detto, il concetto di un file system basato su directory non rientra nell'ambito dei linguaggi c / c ++.

Inoltre, non si desidera la directory di lavoro corrente, ma la directory in cui è in esecuzione il programma, che deve tenere conto di come il programma è arrivato dove si trova, ovvero è stato generato come un nuovo processo tramite un fork , ecc. Per ottenere la directory in cui è in esecuzione un programma, come hanno dimostrato le soluzioni, è necessario ottenere tali informazioni dalle strutture di controllo del processo del sistema operativo in questione, che è l'unica autorità su questa domanda. Quindi, per definizione, è una soluzione specifica per il sistema operativo.

Per il sistema Windows su console è possibile utilizzare il comando di sistema ( dir ). E la console fornisce informazioni sulla directory e così via. Leggi il comando dir su cmd . Ma per i sistemi simili a Unix, non lo so ... Se questo comando viene eseguito, leggi il comando bash. ls non visualizza la directory ...

Esempio:

int main()
{
    system("dir");
    system("pause"); //this wait for Enter-key-press;
    return 0;
}
#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);
}

Il comando bash di linux quale progname segnalerà un percorso per programmare.

Anche se si potesse emettere il comando dal proprio programma e indirizzare l'output su un file tmp e sul programma successivamente legge quel file tmp, non ti dirà se quel programma è quello in esecuzione. Ti dice solo dove si trova un programma con quel nome.

È necessario ottenere il numero ID del processo e analizzare il percorso del nome

Nel mio programma voglio sapere se il programma era eseguito dalla directory bin dell'utente o da un'altra nel percorso o da / usr / bin. / usr / bin conterrebbe la versione supportata. La mia sensazione è che in Linux esiste l'unica soluzione portatile.

Per i percorsi relativi, ecco cosa ho fatto. Sono consapevole dell'età di questa domanda, voglio semplicemente contribuire con una risposta più semplice che funzioni nella maggior parte dei casi:

Supponi di avere un percorso come questo:

"path/to/file/folder"

Per qualche ragione, gli eseguibili basati su Linux realizzati in eclipse funzionano bene con questo. Tuttavia, Windows diventa molto confuso se viene fornito un percorso come questo con cui lavorare!

Come detto sopra, ci sono diversi modi per ottenere il percorso corrente per l'eseguibile, ma il modo più semplice che trovo funzioni un incantesimo nella maggior parte dei casi è quello di aggiungere questo al FRONT del tuo percorso:

"./path/to/file/folder"

Basta aggiungere " ./" dovrebbe farti ordinare! :) Quindi puoi iniziare a caricare da qualsiasi directory desideri, purché sia ??con l'eseguibile stesso.

EDIT: Questo non funzionerà se provi ad avviare l'eseguibile da code :: blocks se è l'ambiente di sviluppo in uso, poiché per qualche ragione code :: blocks non carica le cose nel modo giusto ...: D

EDIT2: Alcune nuove cose che ho scoperto è che se specifichi un percorso statico come questo nel tuo codice (Supponendo che Esempio.data sia qualcosa che devi caricare):

"resources/Example.data"

Se avvii la tua app dalla directory effettiva (o in Windows, crei un collegamento e imposti la directory di lavoro sulla directory della tua app), funzionerà così. Tienilo a mente quando esegui il debug di problemi relativi a percorsi di risorse / file mancanti. (Soprattutto negli IDE che impostano la directory di lavoro errata quando si avvia un exe build dall'IDE)

Su piattaforme POSIX, puoi usare getcwd () .

Su Windows, puoi usare _getcwd () , come uso di getcwd () è stato deprecato.

Per le librerie standard, se Boost fosse abbastanza standard per te, avrei suggerito Boost :: filesystem, ma sembrano aver rimosso la normalizzazione del percorso dalla proposta. Potrebbe essere necessario attendere fino a quando TR2 diventa prontamente disponibile per una soluzione completamente standard.

Boost initial_path () si comporta come getcwd () di POSIX, e non fa nemmeno quello che vuoi da solo, ma accodando argv [0] a nessuno dei due dovrebbe farlo.

Potresti notare che il risultato non è sempre carino: potresti ottenere cose come /foo/bar/../../baz/a.out o / foo / bar // baz / a.out , ma credo che si traduca sempre in un percorso valido che denomina l'eseguibile (nota che le barre consecutive in un percorso sono compresse a una).

In precedenza avevo scritto una soluzione usando envp (il terzo argomento di main () che funzionava su Linux ma non sembrava fattibile su Windows, quindi sono essenzialmente raccomandare la stessa soluzione di qualcun altro in precedenza, ma con l'ulteriore spiegazione del perché sia ??effettivamente corretta anche se i risultati non sono belli.

Come menzionato Minok , non esiste tale funzionalità specificata nello standard C o C ++. Questa è considerata una funzione puramente specifica del sistema operativo ed è specificata nello standard POSIX, ad esempio.

Thorsten79 ha dato buoni suggerimenti, è la libreria Boost.Filesystem. Tuttavia, potrebbe essere scomodo nel caso in cui non si desideri avere dipendenze del tempo di collegamento in forma binaria per il proprio programma.

Una buona alternativa che consiglierei è la raccolta di intestazioni solo al 100% STLSoft C ++ Libraries Matthew Wilson (autore di libri da leggere sul C ++) . La facciata portatile PlatformSTL consente di accedere all'API specifica del sistema: WinSTL per Windows e UnixSTL su Unix, quindi è una soluzione portatile. Tutti gli elementi specifici del sistema sono specificati con l'uso di tratti e criteri, quindi è un quadro estensibile. C'è una libreria di filesystem fornita, ovviamente.

Una soluzione di libreria (anche se so che questo non è stato richiesto). Se ti capita di usare Qt: QCoreApplication :: applicationDirPath ()

Usa realpath () in stdlib.h in questo modo:

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

Funziona a partire da C ++ 11, usando un filesystem sperimentale, e C ++ 14-C ++ 17 e usando un filesystem ufficiale.

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
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top