web-dev-qa-db-fra.com

Comment puis-je obtenir le répertoire à partir duquel un programme est exécuté?

Existe-t-il une méthode indépendante de la plate-forme et indépendante du système de fichiers pour obtenir le chemin d'accès complet du répertoire à partir duquel un programme est exécuté à l'aide de C/C++? Ne pas confondre avec le répertoire de travail actuel. (Merci de ne pas suggérer de bibliothèques, sauf si elles sont standard, comme clib ou STL.)

(S'il n'existe aucune méthode indépendante de la plate-forme/du système de fichiers, les suggestions qui fonctionnent sous Windows et Linux pour des systèmes de fichiers spécifiques sont également les bienvenues.)

245
Ashwin Nanjappa

Voici le code pour obtenir le chemin complet de l'application en cours d'exécution:

Les fenêtres:

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;
164
Mike

Si vous récupérez le répertoire actuel au premier démarrage de votre programme, vous avez effectivement le répertoire à partir duquel votre programme a été démarré. Stocker la valeur dans une variable et y faire référence plus tard dans votre programme. Ceci est différent de le répertoire qui contient le fichier de programme exécutable actuel . Ce n'est pas nécessairement le même répertoire; si quelqu'un exécute le programme à partir d'une invite de commande, le programme est en cours d'exécution est exécuté à partir de le répertoire de travail actuel de l'invite de commande, même si le fichier de programme réside ailleurs.

getcwd est une fonction POSIX prise en charge immédiatement par toutes les plates-formes compatibles POSIX. Vous n’auriez rien à faire de particulier (à part d’incliner les en-têtes de droite unistd.h sous Unix et direct.h sous Windows).

Comme vous créez un programme C, il sera lié à la bibliothèque d'exécution C par défaut à laquelle TOUS les processus du système sont liés (les exceptions spécialement conçues sont évitées) et il inclura cette fonction par défaut. Le CRT n'est jamais considéré comme une bibliothèque externe car il fournit l'interface conforme au standard de base du système d'exploitation.

Sur Windows, la fonction getcwd est déconseillée au profit de _getcwd. Je pense que vous pourriez l'utiliser de cette façon.

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

Ceci est du forum cplusplus

Sur les fenêtres:

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

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

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

Sur 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 );
}
34
Octopus

Si vous voulez une méthode standard sans bibliothèques: Non. Le concept entier d'un répertoire n'est pas inclus dans la norme.

Si vous acceptez le fait que certaines dépendances (portables) sur une bibliothèque presque standard sont acceptables: Utilisez la bibliothèque de système de fichiers de Boost et demandez le initial_path ()

IMHO c'est aussi proche que possible, avec un bon karma (Boost est un ensemble bien établi de bibliothèques de haute qualité)

28
Thorsten79

Le système de fichiers TS est maintenant un standard (pris en charge par gcc 5.3+ et clang 3.9+), vous pouvez donc utiliser current_path()

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

Dans gcc (5.3+) pour inclure le système de fichiers, vous devez utiliser:

#include <experimental/filesystem>

et liez votre code avec le drapeau -lstdc++fs.

Si vous voulez utiliser Filesystem avec Microsoft Visual Studio, alors lisez ceci .

18
Marqin

Je sais qu’il est très tard dans la journée pour répondre à cette question, mais j’ai trouvé qu’aucune de ces réponses ne m’était aussi utile que ma propre solution. Voici un moyen très simple d’obtenir le chemin de votre fichier CWD vers votre dossier 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("/"));
}

Vous pouvez maintenant l'utiliser comme base pour votre chemin relatif. Ainsi, par exemple, j'ai cette structure de répertoire:

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

et je veux compiler mon code source dans bin et écrire un journal pour le tester, je peux simplement ajouter cette ligne à mon code.

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

J'ai essayé cette approche sur Linux en utilisant le chemin complet, alias, etc. et cela fonctionne très bien.

REMARQUE:

Si vous êtes sur Windows, vous devez utiliser un "\" comme séparateur de fichier et non "/". Vous devrez aussi y échapper, par exemple:

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

Je pense que cela devrait fonctionner mais n’a pas encore été testé. Un commentaire serait donc apprécié si cela fonctionne ou un correctif dans le cas contraire. 

16
Sam Redway

Non, il n'y a pas de moyen standard. Je crois que les normes C/C++ ne considèrent même pas l'existence de répertoires (ou d'autres organisations de système de fichiers).

Sous Windows, le paramètre GetModuleFileName () renvoie le chemin complet du fichier exécutable du processus en cours lorsque le paramètre hModule est défini surNULL. Je ne peux pas aider avec Linux.

Vous devez également préciser si vous souhaitez que le répertoire actuel ou le répertoire contenant l'image/l'exécutable du programme réside. En l'état, votre question est un peu ambiguë sur ce point.

8
Michael Burr

Peut-être concaténer le répertoire de travail actuel avec argv [0]? Je ne sais pas si cela fonctionnerait sous Windows, mais sous Linux.

Par exemple:

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

Lorsqu'il est exécuté, il génère:

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

7
Jeremy Ruten

Vous ne pouvez pas utiliser argv [0] à cette fin; il contient généralement le chemin complet de l’exécutable, mais pas nécessairement - le processus peut être créé avec une valeur arbitraire dans le champ. 

De plus, le répertoire en cours et le répertoire avec l'exécutable sont deux choses différentes, donc getcwd () ne vous aidera pas non plus.

Sous Windows, utilisez GetModuleFileName (), sous Linux, lisez/dev/proc / procID / .. fichiers.

6
eugensk00

Pour Win32 GetCurrentDirectory devrait faire l'affaire.

5

Sous Windows, le moyen le plus simple consiste à utiliser la fonction _get_pgmptr dans stdlib.h pour obtenir un pointeur sur une chaîne représentant le chemin absolu de l'exécutable, y compris le nom de l'exécutable.

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

Juste pour empiler tardivement ici, ...

il n'y a pas de solution standard, car les langages sont agnostiques des systèmes de fichiers sous-jacents. Par conséquent, comme d'autres l'ont déjà dit, le concept de système de fichiers basé sur des répertoires dépasse le cadre des langages c/c ++.

en plus de cela, vous ne voulez pas le répertoire de travail actuel, mais le répertoire dans lequel le programme est exécuté, ce qui doit tenir compte de la manière dont le programme est arrivé à son emplacement actuel, c’est-à-dire qu’il a été créé comme un nouveau processus via un fork, etc. Pour obtenir le répertoire dans lequel un programme est exécuté, comme le montrent les solutions, vous devez obtenir ces informations à partir des structures de contrôle de processus du système d'exploitation en question, qui est l'unique autorité en la matière. Ainsi, par définition, c’est une solution spécifique à un système d’exploitation.

3
Minok

Pour le système Windows sur console, vous pouvez utiliser la commande system (dir). Et la console vous donne des informations sur le répertoire, etc. Lisez sur la commande dir à cmd. Mais pour les systèmes de type Unix, je ne sais pas ... Si cette commande est exécutée, lisez la commande bash. ls n'affiche pas le répertoire ...

Exemple:

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

La commande linux bash nom_programme indiquera le chemin du programme.

Même si vous pouviez lancer la commande quelle à partir de votre programme et diriger la sortie vers un fichier tmp et que le programme Lit ensuite ce fichier tmp, il ne vous dira pas si ce programme est en cours d'exécution. Il vous indique uniquement où se trouve un programme portant ce nom.

Ce qui est requis est d’obtenir votre numéro d’identification de processus et d’analyser le chemin du nom. 

Dans mon programme, je veux savoir si le programme a été exécuté à partir du répertoire bin de l'utilisateur ou d'un autre répertoire situé dans le chemin .__ ou de/usr/bin./usr/bin contiendrait la version prise en charge . Mon sentiment est qu’il existe dans Linux une solution portable.

1
Leslie Satenstein

Pour les chemins relatifs, voici ce que j'ai fait. Je suis conscient de l'âge de cette question, je veux simplement apporter une réponse plus simple qui fonctionne dans la majorité des cas:

Disons que vous avez un chemin comme celui-ci:

"path/to/file/folder"

Pour une raison quelconque, les exécutables construits par Linux dans Eclipse fonctionnent bien avec cela. Cependant, les fenêtres deviennent très confuses si un chemin comme celui-ci est utilisé!

Comme indiqué ci-dessus, il existe plusieurs manières d'obtenir le chemin actuel vers l'exécutable, mais la façon la plus simple de trouver un charme dans la plupart des cas est de l'ajouter au FRONT de votre chemin:

"./path/to/file/folder"

Ajouter simplement "./" devrait vous permettre de faire le tri! :) Ensuite, vous pouvez commencer à charger à partir du répertoire de votre choix, à condition que ce soit avec l'exécutable lui-même.

EDIT: Cela ne fonctionnera pas si vous essayez de lancer l'exécutable à partir de code :: blocks si c'est l'environnement de développement utilisé, car pour une raison quelconque, code :: blocks ne charge pas correctement ...: D

EDIT2: Certaines nouvelles choses que j’ai trouvées sont que si vous spécifiez un chemin statique comme celui-ci dans votre code (Assuming Example.data est quelque chose que vous devez charger):

"resources/Example.data"

Si vous lancez ensuite votre application à partir du répertoire réel (ou sous Windows, vous créez un raccourci et définissez le répertoire de travail dans le répertoire de votre application), cela fonctionnera comme cela . Gardez cela à l'esprit lorsque vous résolvez des problèmes chemins de ressources/fichiers. (En particulier dans les IDE qui définissent le mauvais répertoire de travail lors du lancement d'un exécutable depuis l'IDE)

1
FuzzyQuills

Comme Minok l'a mentionné, aucune fonctionnalité de ce type n'est spécifiée dans le standard C ou le standard C++. Ceci est considéré comme une fonctionnalité purement spécifique au système d’exploitation et est spécifié dans le standard POSIX, par exemple.

Thorsten79 a donné une bonne suggestion, c’est la bibliothèque Boost.Filesystem. Cependant, cela peut être gênant si vous ne voulez pas avoir de dépendances de temps de lien sous forme binaire pour votre programme.

Une bonne alternative que je recommanderais est la collecte de 100% en-têtes uniquement Bibliothèques STLSoft C++Matthew Wilson (auteur de livres à lire absolument sur le C++). Il y a une façade portable PlatformSTL donne accès à l'API spécifique au système: WinSTL pour Windows et UnixSTL sous Unix, il s'agit donc d'une solution portable. Tous les éléments spécifiques au système sont spécifiés à l'aide de traits et de règles, ce qui en fait un cadre extensible. Il y a une bibliothèque de système de fichiers fournie, bien sûr.

0
mloskot

La initial_path() de Boost Filesystem se comporte comme la getcwd() de POSIX, pas plus que ce que vous voulez, mais l'ajout de argv[0] à l'une d'elles devrait le faire.

Vous remarquerez peut-être que le résultat n'est pas toujours joli. Vous pouvez obtenir des éléments tels que /foo/bar/../../baz/a.out ou /foo/bar//baz/a.out, mais je pense que cela donne toujours un chemin valide qui nomme l'exécutable (notez que les barres obliques consécutives d'un chemin sont réduites à un).

Auparavant, j'avais écrit une solution utilisant envp (le troisième argument de main() qui fonctionnait sous Linux mais qui ne semblait pas fonctionner sous Windows. Je recommande donc essentiellement la même solution que quelqu'un d'autre auparavant, mais avec l'explication supplémentaire de sa raison. effectivement correct même si les résultats ne sont pas jolis.

0
John Zwinck

Sur les plateformes POSIX, vous pouvez utiliser getcwd () .

Sous Windows, vous pouvez utiliser _getcwd () , car l’utilisation de getcwd () est obsolète.

Pour les bibliothèques standard, si Boost était suffisamment standard pour vous, j'aurais suggéré Boost :: système de fichiers, mais elles semblent avoir supprimé la normalisation du chemin de la proposition. Vous devrez peut-être attendre que TR2 devienne facilement disponible pour une solution entièrement standard.

0
Fruny

Une solution de bibliothèque (même si je sais que cela n’a pas été demandé) . Si vous utilisez Qt: QCoreApplication::applicationDirPath()

0
Joachim

Utilisez realpath() dans stdlib.h comme ceci:

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

Fonctionne à partir de C++ 11, en utilisant un système de fichiers expérimental et en C++ 14-C++ 17 avec un système de fichiers officiel.

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
}
0
TarmoPikaro