¿Cómo obtengo el directorio desde el que se está ejecutando un programa?


¿Existe un método independiente de la plataforma y del sistema de archivos para obtener la ruta completa del directorio desde donde se ejecuta un programa utilizando C/C++? No debe confundirse con el directorio de trabajo actual. (Por favor, no sugiera bibliotecas a menos que sean estándar como clib o STL.)

(Si no hay un método independiente de la plataforma/sistema de archivos, las sugerencias que funcionen en Windows y Linux para sistemas de archivos específicos también son bienvenidas.)

 232
Author: casperOne, 2008-09-27

20 answers

Aquí está el código para obtener la ruta completa a la aplicación ejecutora:

Ventanas:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-13 16:01:28

Si obtiene el directorio actual cuando se inicia su programa por primera vez, entonces efectivamente tiene el directorio desde el que se inició su programa. Almacene el valor en una variable y refiérase a él más adelante en su programa. Esto es distinto de el directorio que contiene el archivo de programa ejecutable actual. No es necesariamente el mismo directorio; si alguien ejecuta el programa desde un símbolo del sistema, entonces el programa se está ejecutando desde el directorio de trabajo actual del símbolo del sistema incluso aunque el archivo del programa vive en otra parte.

Getcwd es una función POSIX y compatible con todas las plataformas compatibles con POSIX. No tendrías que hacer nada especial (aparte de incluir los encabezados correctos unistd.h en Unix y direct.h en windows).

Dado que está creando un programa C, se enlazará con la biblioteca de tiempo de ejecución c predeterminada a la que están vinculados TODOS los procesos del sistema (se evitan excepciones especialmente diseñadas) e incluirá esta función por defecto. La CRT nunca se considera una biblioteca externa porque proporciona la interfaz estándar básica compatible con el sistema operativo.

En Windows la función getcwd ha sido obsoleta a favor de _getcwd. Creo que podrías usarlo de esta manera.

#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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:39

Esto es del foro cplusplus

En windows:

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

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

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

En 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-24 15:59:23

Si desea una forma estándar sin bibliotecas: No. Todo el concepto de directorio no está incluido en el estándar.

Si está de acuerdo en que alguna dependencia (portable) en una lib casi estándar está bien: Use la biblioteca del sistema de archivos de Boost y pregunte por el initial_path().

En mi humilde opinión eso es lo más cercano que puedes conseguir, con buen karma (Boost es un conjunto bien establecido de bibliotecas de alta calidad)

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-27 07:23:51

El sistema de archivos TS ahora es un estándar (y es compatible con gcc 5.3 + y clang 3.9+), por lo que puede usar current_path() función de ella:

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

En gcc (5.3+) para incluir el sistema de archivos necesitas usar:

#include <experimental/filesystem>

Y enlaza tu código con la bandera -lstdc++fs.

Si desea utilizar el sistema de archivos con Microsoft Visual Studio, entonces lea esto.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-11 11:38:29

Sé que es muy tarde en el día para lanzar una respuesta a este, pero encontré que ninguna de las respuestas eran tan útiles para mí como mi propia solución. Una forma muy sencilla de obtener la ruta de su CWD a su carpeta bin es así:

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

Ahora puede usar esto como base para su ruta relativa. Así, por ejemplo, tengo esta estructura de directorios:

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

Y quiero compilar mi código fuente a bin y escribir un registro para probar, solo puedo agregar esta línea a mi codificar.

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

He probado este enfoque en Linux usando ruta completa, alias, etc. y funciona muy bien.

NOTA:

Si está en Windows, debe usar un '\' como separador de archivos, no '/'. Usted tendrá que escapar de esto también por ejemplo:

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

Creo que esto debería funcionar, pero no lo he probado, por lo que se agradecería un comentario si funciona o una corrección si no.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-15 11:30:13

No, no hay una manera estándar. Creo que los estándares de C / C++ ni siquiera consideran la existencia de directorios (u otras organizaciones de sistemas de archivos).

En Windows el GetModuleFileName() devolverá la ruta completa al archivo ejecutable del proceso actual cuando el parámetro hModule se establezca en NULL. No puedo ayudar con Linux.

También debe aclarar si desea el directorio actual o el directorio que el programa imagen/ejecutable reside. Tal como está su pregunta es un poco ambigua en este punto.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-27 07:35:51

Tal vez concatenar el directorio de trabajo actual con argv[0]? No estoy seguro si eso funcionaría en Windows pero funciona en Linux.

Por ejemplo:

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

Cuando se ejecuta, produce:

Jeremy@jeremy-desktop:~/Desktop Desktop ./ test
/ home / jeremy / Desktop/./ 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-27 07:39:11

No se puede utilizar argv[0] para ese propósito, por lo general contiene la ruta completa al ejecutable, pero no nessesarily - proceso podría ser creado con valor arbitrario en el campo.

También ten en cuenta que el directorio actual y el directorio con el ejecutable son dos cosas diferentes, por lo que getcwd() tampoco te ayudará.

En Windows use GetModuleFileName(), en Linux read /dev/proc/ procID/.. file.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-13 04:12:24

Para Win32 GetCurrentDirectory debería hacer el truco.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-27 07:21:01

Para el sistema Windows en la consola puede usar el comando system(dir). Y la consola le da información sobre el directorio y etc. Lea acerca del comando dir en cmd. Pero para sistemas tipo Unix, no lo sé... Si se ejecuta este comando, lea comando bash. ls no muestra el directorio...

Ejemplo:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-10 17:13:27

Solo para apilar tardíamente aquí,...

No hay una solución estándar, porque los lenguajes son agnósticos de los sistemas de archivos subyacentes, por lo que como otros han dicho, el concepto de un sistema de archivos basado en directorios está fuera del alcance de los lenguajes c / c++.

Además de eso, no desea el directorio de trabajo actual, sino el directorio en el que se está ejecutando el programa, lo que debe tener en cuenta cómo el programa llegó a donde está: es decir, fue generado como un nuevo proceso a través de una bifurcación, etc. Para obtener el directorio en el que se está ejecutando un programa, como han demostrado las soluciones, se requiere que obtenga esa información de las estructuras de control de procesos del sistema operativo en cuestión, que es la única autoridad en esta cuestión. Por lo tanto, por definición, es una solución específica del sistema operativo.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-27 23:50:14

En Windows la forma más sencilla es usar la función _get_pgmptr en stdlib.h para obtener un puntero a una cadena que representa la ruta absoluta al ejecutable, incluido el nombre de los ejecutables.

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-19 17:20:58

El comando bash de linux que progname reportará una ruta al programa.

Incluso si uno pudiera emitir el comando which desde dentro de su programa y dirigir la salida a un archivo tmp y al programa posteriormente lee ese archivo tmp, no le dirá si ese programa es el que se ejecuta. Solo le dice dónde se encuentra un programa que tiene ese nombre.

Lo que se requiere es obtener su número de id de proceso, y analizar la ruta al nombre

En mi programa quiero saber si el programa fue ejecutado desde el directorio bin del usuario o desde otro en la ruta o desde/usr / bin. /usr / bin contendría la versión soportada. Mi sensación es que en Linux existe la única solución que es portable.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-22 15:46:54

Para los caminos relativos, esto es lo que hice. Soy consciente de la edad de esta pregunta, simplemente quiero contribuir con una respuesta más simple que funciona en la mayoría de los casos:

Digamos que tienes un camino como este:

"path/to/file/folder"

Por alguna razón, los ejecutables construidos en Linux en eclipse funcionan bien con esto. Sin embargo, Windows se confunde mucho si se le da un camino como este para trabajar con!

Como se indicó anteriormente, hay varias formas de obtener la ruta actual al ejecutable, pero la forma más fácil es encuentra obras un amuleto en la mayoría de los casos es anexar esto al FRENTE de tu camino:

"./path/to/file/folder"

Simplemente añadiendo "./ "debería conseguirle ordenado! :) Entonces puede comenzar a cargar desde cualquier directorio que desee, siempre y cuando sea con el ejecutable en sí.

EDIT: Esto no funcionará si intentas lanzar el ejecutable desde code::blocks si ese es el entorno de desarrollo que se está utilizando, ya que por alguna razón code::blocks no carga bien las cosas... : D

EDIT2: Algunas cosas nuevas que tengo encontrado es que si especifica una ruta estática como esta en su código (Suponiendo Ejemplo.datos es algo que necesita cargar):

"resources/Example.data"

Si luego inicia su aplicación desde el directorio real (o en Windows, crea un acceso directo y establece el directorio de trabajo en su directorio de aplicación), entonces funcionará así. Tenga esto en cuenta al depurar problemas relacionados con rutas de recursos/archivos faltantes. (Especialmente en IDEs que establecen el dir de trabajo incorrecto al lanzar un exe de compilación desde el 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-02 01:34:04

En plataformas POSIX, puedes usar getcwd().

En Windows, puede usar _getcwd(), ya que el uso de getcwd() ha sido obsoleto.

Para las bibliotecas estándar, si Boost fuera lo suficientemente estándar para usted, habría sugerido Boost::filesystem, pero parecen haber eliminado la normalización de rutas de la propuesta. Es posible que tenga que esperar hasta que TR2 esté fácilmente disponible para obtener una solución completamente estándar.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-27 07:31:38

El initial_path() de Boost Filesystem se comporta como el getcwd() de POSIX, y ninguno de los dos hace lo que quiere por sí mismo, pero añadiendo argv[0] a cualquiera de ellos debería hacerlo.

Puede notar que el resultado no siempre es bonito you puede obtener cosas como /foo/bar/../../baz/a.out o /foo/bar//baz/a.out, pero creo que siempre resulta en una ruta válida que nombra el ejecutable (tenga en cuenta que las barras oblicuas consecutivas en una ruta se contraen en una).

Anteriormente escribí una solución usando envp (el tercer argumento de main() que funcionó en Linux, pero no parecía viable en Windows, por lo que esencialmente estoy recomendando la misma solución que alguien lo hizo anteriormente, pero con la explicación adicional de por qué es realmente correcta, incluso si los resultados no son bonitos.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-24 01:24:59

Como Minok mencionado, no hay tal funcionalidad especificada en el estándar ini C o en el estándar C++. Esto se considera una característica puramente específica del sistema operativo y se especifica en el estándar POSIX, por ejemplo.

Thorsten79 ha dado una buena sugerencia, es Boost.Biblioteca del sistema de archivos. Sin embargo, puede ser inconveniente en caso de que no desee tener dependencias de tiempo de enlace en forma binaria para su programa.

Una buena alternativa que recomendaría es la colección de 100% solo encabezados STLSoft C++ Libraries Matthew Wilson (autor de libros de lectura obligatoria sobre C++). No es portable facade PlatformSTL da acceso a la API específica del sistema: WinSTL para Windows y UnixSTL en Unix, por lo que es una solución portátil. Todos los elementos específicos del sistema se especifican con el uso de rasgos y políticas, por lo que es un marco extensible. Por supuesto, se proporciona una biblioteca del sistema de archivos.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-28 00:26:18

Una solución de biblioteca(aunque sé que esto no se pidió). Si usa 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-04 09:38:03