Bonjour à tous,
Je recherche le moyen le plus simple (au sens "moins de lignes de code") de récupérer le répertoire de travail d'un programme.
Supposons que le programme ait besoin d'ouvrir un fichier data.txt situé dans le même répertoire que l'exécutable. Le plus simple est d'écrire :
f=fopen("data.txt","r");
Mais si j'appelle le programme d'un autre emplacement que celui de l'exécutable, ça ne marche pas. Il faut donc récupérer le répertoire de travail.
Voici les deux méthodes les plus simples que j'ai trouvées :
Méthode 1 :
#define _GNU_SOURCE
#include <libgen.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *f;
char *racine;
char *chemin;
char nom_fichier[]="/data.txt";
racine=strdupa(argv[0]);
chemin=malloc(strlen(dirname(racine))+strlen(nom_fichier)+1);
strcpy(chemin,racine);
strcat(chemin,nom_fichier);
if ((f=fopen(chemin,"r")) != NULL)
{
...
Si l'on veut se passer de l'extension GNU, on peut remplacer racine=strdupa(argv[0]);
par :
racine=malloc(strlen(argv[0])+1);
strcpy(racine,argv[0]);
Bien sûr ceci a peu d'intérêt étant donné le caractère anecdotique des systèmes d'exploitations autres que GNU-Linux.
Méthode 2 :
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *f;
int l;
char *chemin;
char nom_fichier[]="data.txt";
l=strlen(argv[0])-strlen(program_invocation_short_name);
chemin=malloc(l+strlen(nom_fichier)+1);
memcpy(chemin,argv[0],l);
strcat(chemin,nom_fichier);
if ((f=fopen(chemin,"r")) != NULL)
{
...
On peut simplifier encore plus en se passant des malloc en assignant une dimension fixe aux chaînes, mais c'est moins propre.
Et vous comment faites vous ?
# getcwd ?
Posté par warwick . Évalué à 3.
https://linux.die.net/man/3/getcwd ?
[^] # Re: getcwd ?
Posté par David Demelier (site web personnel) . Évalué à 3.
Là où est l'exécutable et le répertoire courant sont deux choses différentes.
git is great because linus did it, mercurial is better because he didn't
# Répertoire du fichier exécutable
Posté par 🚲 Tanguy Ortolo (site web personnel) . Évalué à 8.
Objection. Tu veux récupérer le répertoire du fichier exécutable. Le répertoire de travail, que tu n'as pas modifié, c'est celui depuis lequel tu as lancé le programme.
[^] # Re: Répertoire du fichier exécutable
Posté par Barnabé . Évalué à 1.
En tenant compte de cette remarque je proposerai
[^] # Re: Répertoire du fichier exécutable
Posté par harlock974 . Évalué à 2.
Oui tu as raison. Après vérification, il y a bien une confusion terminologique de ma part.
Je croyais que le répertoire de travail était celui où le programme travaille. C'est à dire celui où se trouve l'exécutable et les fichiers annexes. En fait c'est bien le répertoire d'où il est lancé.
# Bonne pratique ?
Posté par gUI (Mastodon) . Évalué à 4. Dernière modification le 15 mars 2023 à 14:11.
Je ne suis pas certain que ce soit une bonne pratique. En tous cas je te conseille de garder ce comportement pour une utilisation très précise et parfaitement maîtrisée (par exemple un système embarqué dont tu es le concepteur).
En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.
[^] # Re: Bonne pratique ?
Posté par harlock974 . Évalué à 1.
Qu'est ce qui n'est pas une bonne pratique ?
[^] # Re: Bonne pratique ?
Posté par gUI (Mastodon) . Évalué à 7. Dernière modification le 15 mars 2023 à 19:12.
D'écrire un fichier à l'emplacement d'où est l'exécutable : en général les fichiers temporaires vont dans
/tmp
, le fichiers de config dans$HOME
etc.Peut-être que l'exécutable est dans un répertoire où l'utilisateur n'a pas les droits (cas fréquent sur un système classique), ou l'impossibilité de lancer l'exécutable depuis un répertoire en lecture seule etc.
En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.
# C'est le genre de remarque qui a tendance à m'agacer
Posté par totof2000 . Évalué à 0. Dernière modification le 15 mars 2023 à 14:42.
Dans ce cas inutile de coder pour du GNU Linux étant donné le caractère anecdotique des systèmes autre que windows.
Après je ne dis pas qu'il faille tout rendre portable sur tous les systèmes, mais si ça coute peu de faire quelque chose qui marche partout, pourquoi s'en priver ?
[^] # Re: C'est le genre de remarque qui a tendance à m'agacer
Posté par harlock974 . Évalué à 2.
Ne le prends pas mal. C'était juste une petite blague visant à valoriser mon système d'exploitation préféré…
# Nope
Posté par woke . Évalué à 1.
man 3p exec
man 3 exec
Bonus :
man proc
man hier
# Portable ou pas portable ?
Posté par David Demelier (site web personnel) . Évalué à 2.
En pas portable (Linux only) tu peux simplement lire /proc/self/exe. En très portable c'est plutôt compliqué mais il existe des modules sympathiques comme whereami
git is great because linus did it, mercurial is better because he didn't
# Erreur possible avec malloc ?
Posté par harlock974 . Évalué à 3.
Il me semble qu'il y a un truc qui ne va pas dans mon code, ici :
Le memcpy ne rajoute pas de caractère nul à la fin donc si l'espace alloué par malloc n'est pas vide, chemin ne sera pas une chaîne et le strcat peut planter…
[^] # Re: Erreur possible avec malloc ?
Posté par Tonton Th (Mastodon) . Évalué à 3.
C'est normal, pas d'inquiétude,
memcpy
, c'est fait pour copier de la mémoire et pas des chaines de caractères. Pour ça, il faut utiliserstrcpy
. Il faut regarder les deux manpages et bien capter la différence entre les deux.Le C, c'est réjouissant :)
[^] # Re: Erreur possible avec malloc ?
Posté par harlock974 . Évalué à 2.
Oui je connais bien la différence entre
memcpy(chaîne1,chaîne2,longueur)
etstrcpy(chaîne1,chaîne2)
; mais dans ce cas on ne veut copier qu'une partie deargv[0]
, d'où l'usage dememcpy
avec le paramètre "longueur".Donc dans le code, il faut en fait remplacer
malloc
parcalloc
, qui initialise "chemin" en le remplissant avec des caractères nuls.# Version finale
Posté par harlock974 . Évalué à 1.
Voici la version finale, où j'espère ne pas avoir fait d'erreur dans les allocations mémoires. Elle a pour avantage d'être portable, de ne pas utiliser de bibliothèques exotiques, et de conserver la valeur du chemin de l'exécutable (variable
racine
) :[^] # Re: Version finale
Posté par Tonton Th (Mastodon) . Évalué à 2. Dernière modification le 19 mars 2023 à 09:30.
Et tu peux aussi rajouter un
perror(nom_fichier);
avant le dernierputs
.Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.